A. 机器人足球
#include
#include
#include
using namespace std;
double dis(int x1, int y1, int x2, int y2) {
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main() {
int x, y;
scanf("%d%d", &x, &y);
double d = dis(x,y,100,10)-10;
printf("%.3lf\n",max(d,0.));
}
B. 纸牌识别
#include
#include
#include
using namespace std;
typedef pair pii;
char x;
int y;
int a[200];
set s;
int main() {
a['P']=a['K']=a['H']=a['T']=13;
while (~scanf(" %c%d", &x, &y)) {
if (s.count(pii(x,y))) return puts("GRESKA"),0;
s.insert(pii(x,y));
--a[x];
}
printf("%d %d %d %d\n",a['P'],a['K'],a['H'],a['T']);
}
C. 卡牌对决
#include
#include
#include
#include
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
const int N = 1e5+10;
int n, a[N];
set
Bob, Alice;
int main() {
scanf("%d", &n);
REP(i,1,n) {
scanf("%d",a+i);
Bob.insert(a[i]);
}
REP(i,1,2*n) if (!Bob.count(i)) Alice.insert(i);
int ans = 0;
sort(a+1,a+1+n/2,greater());
REP(i,1,n/2) {
int x = *(--Alice.end());
if (x>a[i]) ++ans, Alice.erase(x);
}
sort(a+1+n/2,a+1+n);
REP(i,1,n/2) {
int x = *Alice.begin();
if (x
#include
#include
#include
#include
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define pb push_back
using namespace std;
typedef long long ll;
const int N = 5e4+10;
int n, m;
struct _ {
int to,w;
_ (int to=0,int w=0) :to(to),w(w) {}
};
vector<_> g1[N], g2[N], g3[N];
ll d1[N], d2[N], d3[N];
int vis[N], u[N], v[N], p[N], q[N];
struct node {
int id;
ll w;
node (int id=0, ll w=0) :id(id),w(w) {}
bool operator < (const node &rhs) const {
return w>rhs.w;
}
};
priority_queue pq;
void dij(vector<_> g[], ll d[], int s) {
memset(d,0x3f,sizeof d1);
memset(vis,0,sizeof vis);
pq.push(node(s,d[s]=0));
while (pq.size()) {
int u = pq.top().id; pq.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i=0; id1[u[i]]) ++c;
if (d2[v[i]]+q[i]>d2[u[i]]) ++c;
g3[u[i]].pb(_(v[i],c));
}
dij(g3,d3,1);
printf("%lld\n", d3[n]);
}
E.现代艺术
枚举对称轴, 最多O(n)O(n)条, 再暴力O(nlogn)O(nlogn)check, 复杂度
O(nlogn)O(nlogn). 比赛的时候脑抽了把对称轴想成O(n2)O(n2)的了.... 防止浮点误差,
就没用 double 存, 直接对直线暴力约分了
#include
#include
#include
#include
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define x first
#define y second
using namespace std;
typedef pair pii;
int gcd(int x, int y) {return y?gcd(y,x%y):x;}
const int N = 1e3+10;
int n;
pii a[N];
set s;
int chk(int A, int B, int C) {
REP(i,1,n) {
int u = A*a[i].x+B*a[i].y+C;
int v = A*A+B*B;
if (2*u*A%v||2*u*B%v) return 0;
int xx = a[i].x-2*u*A/v, yy = a[i].y-2*u*B/v;
if (!s.count(pii(xx,yy))) return 0;
}
return 1;
}
struct line {
int a,b,c;
line () {}
line (int A, int B, int C) {
if (!A&&!B) throw;
if (!A&&!C) a=c=0,b=1;
else if (!B&&!C) b=c=0,a=1;
else {
if (!C) {
if (A<0) A=-A,B=-B,C=-C;
int g = gcd(A,abs(B));
a = A/g, b = B/g, c = 0;
}
else if (!B) {
if (A<0) A=-A,B=-B,C=-C;
int g = gcd(A,abs(C));
a = A/g, b = 0, c = C/g;
}
else if (!A) {
if (B<0) A=-A,B=-B,C=-C;
int g = gcd(B,abs(C));
a = 0, b = B/g, c = C/g;
}
else {
if (A<0) A=-A,B=-B,C=-C;
int g = gcd(gcd(A,abs(B)),abs(C));
a = A/g, b = B/g, c = C/g;
}
}
}
bool operator < (const line &rhs) const {
if (a!=rhs.a) return a q;
int main() {
scanf("%d", &n);
REP(i,1,n) {
scanf("%d%d", &a[i].x, &a[i].y);
s.insert(a[i]);
}
REP(i,2,n) {
int A = 2*(a[i].x-a[1].x), B = 2*(a[i].y-a[1].y), C = -A*(a[1].x+a[i].x)/2-B*(a[1].y+a[i].y)/2;
if (chk(A,B,C)) q.insert(line(A,B,C));
A = a[i].y-a[1].y, B = a[1].x-a[i].x, C = -A*a[1].x-B*a[1].y;
if (chk(A,B,C)) q.insert(line(A,B,C));
}
printf("%d\n", (int)q.size());
}
F.割草
最小割, 注意到若要改变地形一定是改变一整个连通块, 对SS 向所有低点的连通块连边,
流量为改造整个连通块的花费, 所有高点的连通块向TT 连边, 流量为改造连通块的花费,
相邻连通块连边, 流量为除草机经过两个连通块的燃油花费. 那么显然最小割就为答案.
#include
#include
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
typedef long long ll;
const int N = 1e6+10, INF = 0x3f3f3f3f;
int n, m, a, b, S, T;
char s[55][55];
struct edge {
int v,next;
ll w;
edge () {}
edge (int v,int next,ll w) :v(v),w(w),next(next) {}
} e[N];
int head[N], dep[N], vis[N], cur[N], cnt=1;
queue Q;
void add(int u, int v, ll w) {
e[++cnt] = edge(v,head[u],w);
head[u] = cnt;
e[++cnt] = edge(u,head[v],0);
head[v] = cnt;
}
int bfs() {
REP(i,1,T) dep[i]=INF,vis[i]=0,cur[i]=head[i];
dep[S]=0,Q.push(S);
while (Q.size()) {
int u = Q.front(); Q.pop();
for (int i=head[u]; i; i=e[i].next) {
if (dep[e[i].v]>dep[u]+1&&e[i].w) {
dep[e[i].v]=dep[u]+1;
Q.push(e[i].v);
}
}
}
return dep[T]!=INF;
}
ll dfs(int x, ll w) {
if (x==T) return w;
ll used = 0;
for (int i=cur[x]; i; i=e[i].next) {
cur[x] = i;
if (dep[e[i].v]==dep[x]+1&&e[i].w) {
int flow = dfs(e[i].v,min(w-used,e[i].w));
if (flow) {
used += flow;
e[i].w -= flow;
e[i^1].w += flow;
if (used==w) break;
}
}
}
return used;
}
ll dinic() {
ll ans = 0;
while (bfs()) ans+=dfs(S,1e18);
return ans;
}
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
int fa[N], sz[N], cost[3000][3000];
int id(int x, int y) {
return (x-1)*m+y;
}
int Find(int x) {return fa[x]?fa[x]=Find(fa[x]):x;}
void add(int x, int y) {
x = Find(x), y = Find(y);
if (x!=y) fa[x]=y,sz[y]+=sz[x];
}
int main() {
scanf("%d%d%d%d", &n, &m, &a, &b);
REP(i,1,n) scanf("%s",s[i]+1);
REP(i,1,n) REP(j,1,m) sz[id(i,j)]=1;
REP(i,1,n) REP(j,1,m) {
REP(k,0,3) {
int x=i+dx[k],y=j+dy[k];
if (s[i][j]==s[x][y]) add(id(i,j),id(x,y));
}
}
REP(i,1,n) REP(j,1,m) {
if (i!=n&&s[i][j]!=s[i+1][j]) {
int u = Find(id(i,j)), v = Find(id(i+1,j));
if (s[i][j]=='.') swap(u,v);
cost[u][v] += a;
}
if (j!=m&&s[i][j]!=s[i][j+1]) {
int u = Find(id(i,j)), v = Find(id(i,j+1));
if (s[i][j]=='.') swap(u,v);
cost[u][v] += a;
}
}
REP(i,1,n*m) REP(j,1,n*m) if (cost[i][j]) add(i,j,cost[i][j]);
S = n*m+1, T = S+1;
REP(i,1,n) REP(j,1,m) if (Find(id(i,j))==id(i,j)) {
if (s[i][j]=='#') add(S,id(i,j),(ll)sz[id(i,j)]*b);
else add(id(i,j),T,(ll)sz[id(i,j)]*b);
}
printf("%lld\n", dinic());
}
G.括号序列
dpdp 求出长为xx, 左括号比右括号多yy 个时的方案数. 然后从前往后枚举, 若放'('的方案
数不少于kk 则放'(', 否则放')'.
注意方案数是指数级, 会爆 long long.
#include
#define REP(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
typedef long long ll;
const int N = 2010;
int n, k;
ll f[N][N];
char ans[N];
int main() {