http://codeforces.com/gym/101078
和ysy、方老师一起打的virtual
打的不是很好...下面按过题顺序放一下过的题的题(dai)解(ma)。
A
给两个1~n的排列,把它们割成尽量短的一些段,使得每一段sort之后一样。
随便写个hash了事(1min交是因为之前顺手写了这题)
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <sstream> #include <stack> #include <iomanip> using namespace std; #define pb push_back #define mp make_pair typedef pair<int,int> pii; typedef long long ll; typedef double ld; typedef vector<int> vi; #define fi first #define se second #define fe first #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);} #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);} #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);} #define es(x,e) (int e=fst[x];e;e=nxt[e]) #define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");} #ifdef LOCAL #define TIMER cerr<<clock()<<"ms\n" #else #define TIMER #endif #define SZ 666666 int n,a[SZ],b[SZ]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=1;i<=n;i++) scanf("%d",b+i); int ca1=0,ca2=0,ca3=1,cb1=0,cb2=0,cb3=1; int lst=0; for(int i=1;i<=n;i++) { ca1+=a[i]; cb1+=b[i]; ca2^=a[i]; cb2^=b[i]; ca3*=a[i]+(233^n)+666; cb3*=b[i]+(233^n)+666; if(ca1!=cb1||ca2!=cb2||ca3!=cb3);else { printf("%d-%d ",lst+1,i); lst=i; ca1=0,ca2=0,ca3=1,cb1=0,cb2=0,cb3=1; } } puts(""); } }
D
有一排洞,从1开始左到右编号,对于每个m,如果m是偶数,那么m和m/2有一条绳子相连,如果m是奇数,m与3m+1有一条绳子相连。
现在在n和n+1这两个洞中间劈一刀,问会砍断多少条绳子。
推推公式...ysy写的
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; int t,n; inline int s(int l,int r) { if(!(l&1)) l++; if(!(r&1)) r--; return (r-l)/2+1; } int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); printf("%d\n",n-n/2+s((n-1)/3+1,n)); } return 0; }
L
有一个01串,现在要通过交换变成前面全是0,后面全是1。
交换i、j,i<=j需要sqrt(j-i)的代价,求最小代价。
注意到(目测出)sqrt(a+b+c)+sqrt(b)<sqrt(a+b)+sqrt(b+c)(因为sqrt增长越来越慢),那么我们只要倒着暴力枚举,能换就换。
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <sstream> #include <stack> #include <iomanip> using namespace std; #define pb push_back #define mp make_pair typedef pair<int,int> pii; typedef long long ll; typedef double ld; typedef vector<int> vi; #define fi first #define se second #define fe first #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);} #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);} #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);} #define es(x,e) (int e=fst[x];e;e=nxt[e]) #define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");} #ifdef LOCAL #define TIMER cerr<<clock()<<"ms\n" #else #define TIMER #endif #define SZ 666666 char s[SZ]; char ep[SZ]; int n; int main() { scanf("%s",s); n=strlen(s); int zero=0; for(int i=0;i<n;i++) zero+=s[i]=='0'; for(int i=0;i<n;i++) ep[i]=(i>=zero)+48; double ans=0; for(int i=0;i<n;i++) { if(s[i]==ep[i]) continue; for(int j=n-1;j>=i+1;j--) { if(s[j]!=ep[i]) continue; swap(s[i],s[j]); ans+=sqrt(j-i); break; } } printf("%.11lf\n",ans); }
C
有一个3*3*n的立方体,每一块可以和相邻块匹配,求全部匹配上的方案数。
十分难写的状压dp,ysy码的
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; int t,n,f[5010][600],g[600][600],a[600][600],x[10][10],q=10007; inline int dfs(int i,int j) { if(i>3) return 1; if(j>3) return dfs(i+1,1); if(!x[i][j]) return dfs(i,j+1); int p=0; if(x[i][j+1]) { x[i][j]=0; x[i][j+1]=0; p+=dfs(i,j+1); x[i][j]=1; x[i][j+1]=1; } if(x[i+1][j]) { x[i][j]=0; x[i+1][j]=0; p+=dfs(i,j+1); x[i][j]=1; x[i+1][j]=1; } return p; } inline void js(int n,int m) { int i,j; for(i=0;i<9;i++) if((n&(1<<i)) && (m&(1<<i))) return; else if((n&(1<<i)) || (m&(1<<i))) x[i/3+1][i%3+1]=0; else x[i/3+1][i%3+1]=1; g[n][m]=dfs(1,1); a[n][++a[n][0]]=m; } int main() { int i,j,k; n=5000; for(i=0;i<512;i++) for(j=0;j<512;j++) js(i,j); f[0][0]=1; for(i=1;i<=n;i++) for(j=0;j<512;j++) for(k=1;k<=a[j][0];k++) f[i][a[j][k]]=(f[i][a[j][k]]+f[i-1][j]*g[j][a[j][k]])%q; scanf("%d",&t); while(t--) { scanf("%d",&n); printf("%d\n",f[n][0]); } return 0; }
F
交互库走迷宫,最后输出最短路径。
一波dfs即可,注意细节。
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <sstream> #include <stack> #include <iomanip> using namespace std; #define pb push_back typedef pair<int,int> pii; typedef long long ll; typedef double ld; typedef vector<int> vi; #define fi first #define se second #define fe first #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);} #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);} #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);} #define es(x,e) (int e=fst[x];e;e=nxt[e]) #define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");} #ifdef LOCAL #define TIMER cerr<<clock()<<"ms\n" #else #define TIMER #endif #define SZ 666666 int dx[]={1,-1,0,0},dy[]={0,0,1,-1}; int npp[233]; bool mp[233][233][5]; int ex=-1,ey=-1; bool vis[233][233]; char tmp[2333],fm[]={"NSEW"}; #define P 101 bool& Vis(int a,int b) { return vis[a+P][b+P]; } bool* Mp(int a,int b) { return mp[a+P][b+P]; } #define FFF fflush(NULL); void dfs(int x,int y) { Vis(x,y)=1; scanf("%s",tmp); for(int i=0;tmp[i];i++) { if(tmp[i]=='*') { ex=x; ey=y; } else Mp(x,y)[npp[tmp[i]]]=1; } for(int i=0;i<4;i++) { if(!Mp(x,y)[i]) continue; if(Vis(x+dx[i],y+dy[i])) continue; printf("%c\n",fm[i]); FFF dfs(x+dx[i],y+dy[i]); printf("%c\n",fm[i^1]); FFF scanf("%s",tmp); } } pii ps[SZ]; int dis[233][233]; int& Dis(int a,int b) { return dis[a+P][b+P]; } void bfs() { memset(dis,127/3,sizeof(dis)); int inf=dis[0][0]; int h=0,t=0; Dis(0,0)=0; ps[t++]=pii(0,0); while(h^t) { pii x=ps[h++]; for(int k=0;k<4;k++) { if(!Mp(x.fi,x.se)[k]) continue; if(Dis(x.fi+dx[k],x.se+dy[k])!=inf) continue; Dis(x.fi+dx[k],x.se+dy[k])=Dis(x.fi,x.se)+1; ps[t++]=pii(x.fi+dx[k],x.se+dy[k]); } } } int T; int main() { npp['N']=0; npp['S']=1; npp['E']=2; npp['W']=3; scanf("%d",&T); while(T--) { ex=-2333, ey=-2333; memset(mp,0,sizeof(mp)); memset(vis,0,sizeof(vis)); dfs(0,0); if(ex==-2333) { puts("-1"); FFF continue; } memset(vis,0,sizeof(vis)); bfs(); printf("%d\n",Dis(ex,ey)); FFF } }
I
叫你写一个编辑器,可以指针左移,指针右移,打一个字母。
写个链表,方老师写的。
# include <stdio.h> # include <string.h> using namespace std; int test; char str[1300000]; int pre[1300000], nxt[1300000], s[1300000], cur=0, siz=0, sz=0; int main() { scanf("%d", &test); while(test--) { for (int i=0; i<=1000000; ++i) pre[i]=nxt[i]=s[i]=0; cur=0,siz=0,sz=0; scanf("%s", str); sz=strlen(str); for (int i=0; i<sz; ++i) { if(str[i] == '<') { if(cur != 0) cur = pre[cur]; } else if(str[i] == '>') { if(nxt[cur] != 0) cur = nxt[cur]; } else if(str[i] == '-') { if(cur) { nxt[pre[cur]] = nxt[cur]; pre[nxt[cur]] = pre[cur]; cur = pre[cur]; } } else { ++siz; nxt[siz] = nxt[cur]; pre[siz] = cur; nxt[cur] = siz; int NEXT = nxt[siz]; pre[NEXT] = siz; s[siz] = str[i]; cur=siz; } } int pos = nxt[0]; while(pos != 0) { printf("%c", (char)s[pos]); pos=nxt[pos]; } puts(""); } }
E
w*h的矩形内有c个圆,给定圆心半径,圆两两不相交(可能相离、相切),求矩形内一个最大的圆使得与任何给定圆不交,输出半径,相对/绝对误差1e-6。
瞎退火,似乎调参挺蛋疼的,ysy写的。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> #include<time.h> using namespace std; int t,a,b,n,x[51],y[51],r[51]; double sx,sy,sr,tx[1000],ty[1000],tr[1000],p; int main() { srand(time(NULL)); int i,j,l; double k,q; scanf("%d",&t); while(t--) { scanf("%d%d%d",&a,&b,&n); for(i=1;i<=n;i++) scanf("%d%d%d",&x[i],&y[i],&r[i]); p=0; for(i=1;i<=10;i++) { sx=double(((rand()<<15)+rand())%(10*a+1))/10; sy=double(((rand()<<15)+rand())%(10*b+1))/10; sr=min(min(sx,a-sx),min(sy,b-sy)); for(j=1;j<=n;j++) sr=min(sr,sqrt((sx-x[j])*(sx-x[j])+(sy-y[j])*(sy-y[j]))-r[j]); for(k=1e6;k>1e-9;k*=0.9) { for(l=1;l<=10;l++) { q=double(((rand()<<15)+rand())%6283)/1000; tx[l]=sx+k*sin(q); ty[l]=sy+k*cos(q); tx[l]=min(max(tx[l],0.0),double(a)); ty[l]=min(max(ty[l],0.0),double(b)); tr[l]=min(min(tx[l],a-tx[l]),min(ty[l],b-ty[l])); for(j=1;j<=n;j++) tr[l]=min(tr[l],sqrt((tx[l]-x[j])*(tx[l]-x[j])+(ty[l]-y[j])*(ty[l]-y[j]))-r[j]); } for(l=1;l<=10;l++) if(tr[l]>sr) { sx=tx[l]; sy=ty[l]; sr=tr[l]; } } p=max(p,sr); } printf("%.9lf\n",p); } return 0; }
J
给出一个填字游戏,有横着的和竖着的,横着的互相不交,竖着的互相不交,现在填上去发现横竖有一些交叉的地方不一样,不能共存。于是让你求出最多的可以共存的。
把不能共存的连边,就是要求二分图最大独立集。n-最大匹配即可。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> #include <vector> #include <limits> #include <set> #include <map> using namespace std; namespace gg { #define SZ 666666 int n,M=1;typedef long long ll; int fst[SZ],nxt[SZ],vb[SZ],cap[SZ]; void _ad_dl(int a,int b,int c) {++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;cap[M]=c;} void ad_dl(int a,int b,int c) {_ad_dl(a,b,c); _ad_dl(b,a,0);} int S,T,q[SZ],d[SZ]; bool bfs() { for(int i=1;i<=n+1;i++) d[i]=-1; d[S]=0; q[1]=S; int h=1,t=2; while(h!=t) { int cur=q[h++]; for(int e=fst[cur];e;e=nxt[e]) { int b=vb[e]; if(d[b]==-1&&cap[e]) d[b]=d[cur]+1, q[t++]=b; } } return d[T]!=-1; } int dfs(int x,int f) { if(f<=0) return 0; if(x==T) return f; int ca=0; for(int e=fst[x];e;e=nxt[e]) { int b=vb[e]; if(d[b]!=d[x]+1) continue; int w=dfs(b,min(cap[e],f-ca)); cap[e]-=w; cap[e^1]+=w; ca+=w; if(ca==f) break; } if(!ca) d[x]=-1; return ca; } #define inf 1000000000 int dinic() { int ans=0; while(bfs()) ans+=dfs(S,inf); return ans; } int Tat,h,v,x1[SZ],y1[SZ],x2[SZ],y2[SZ]; int s1l[SZ],s2l[SZ]; char s1[503][1003],s2[503][1003]; int main() { //freopen("test.txt","r",stdin); scanf("%d",&Tat); while(Tat--) { M=1; scanf("%d%d",&h,&v); for(int i=1;i<=h;i++) { scanf("%d%d ",x1+i,y1+i); gets(s1[i]); s1l[i]=strlen(s1[i]); } for(int i=1;i<=v;i++) { scanf("%d%d ",x2+i,y2+i); gets(s2[i]); s2l[i]=strlen(s2[i]); } n=h+v; S=++n; T=++n; for(int i=1;i<=n;i++) fst[i]=0; for(int i=1;i<=h;i++) ad_dl(S,i,1); for(int i=1;i<=v;i++) ad_dl(i+h,T,1); for(int i=1;i<=h;i++) { for(int j=1;j<=v;j++) { int xx=x2[j],yy=y1[i]; bool ok=1; if(x1[i]<=xx&&xx<=x1[i]+s1l[i]-1) { if(y2[j]<=yy&&yy<=y2[j]+s2l[j]-1) { if(s1[i][xx-x1[i]]==s2[j][yy-y2[j]]) ok=1; else ok=0; } } //cout<<i<<","<<j<<" "<<ok<<"\n"; if(!ok) ad_dl(i,j+h,1); } } printf("%d\n",h+v-dinic()); } } } int main() { gg::main(); }
接下来就卡题了...打出gg