第六周 8.23-8.29
8.23
POJ 3311 Hie with the Pie
TSP问题。
先跑一遍Floyd。再状压dp。
dp[i][j]表示经过集合i的点最后到达j的最短距离。
转移:取集合i中任意一点j。如果i中只有j。dp[i][j]=dist[i][j]。
如果i中还有其他点k。dp[i][j]=min(dp[i\{j}][k]+dist[k][j])。
1 # include <iostream> 2 # include <cstdio> 3 # include <algorithm> 4 using namespace std; 5 # define INF 1000000000 6 int dist[11][11],dp[1<<10][10]; 7 8 int main(void) 9 { 10 int n; 11 while(~scanf("%d",&n)&&n) 12 { 13 for(int i=0;i<=n;i++) 14 for(int j=0;j<=n;j++) 15 scanf("%d",&dist[i][j]); 16 for(int k=0;k<=n;k++) 17 for(int i=0;i<=n;i++) 18 for(int j=0;j<=n;j++) 19 dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]); 20 for(int i=1;i<(1<<n);i++) 21 { 22 for(int j=1;j<=n;j++) 23 { 24 if(i==(1<<(j-1))) dp[i][j]=dist[0][j]; 25 else if(i&(1<<(j-1))) 26 { 27 dp[i][j]=INF; 28 for(int k=1;k<=n;k++) 29 { 30 if(k==j) continue; 31 if(i&(1<<(k-1))) dp[i][j]=min(dp[i][j],dp[i^(1<<(j-1))][k]+dist[k][j]); 32 } 33 } 34 } 35 } 36 int ans=INF; 37 for(int i=1;i<=n;i++) ans=min(ans,dp[(1<<n)-1][i]+dist[i][0]); 38 printf("%d\n",ans); 39 } 40 return 0; 41 }
UVA 11205 The broken pedometer
题意:在P列中选择最少的列。使得每行排列都不同。
二进制枚举选择列的所有情况。
判断排列是否相同可以采用给每一位按二进制赋权。用一个一维数组标记。
如果枚举的排列选择的列数大于当前答案直接剪掉。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 int a[101][16],vis[1<<15]; 6 7 int main(void) 8 { 9 int T ; cin>>T; 10 while(T--) 11 { 12 int P,N; 13 scanf("%d%d",&P,&N); 14 for(int i=1;i<=N;i++) 15 for(int j=1;j<=P;j++) 16 scanf("%d",&a[i][j]); 17 int ans=P; 18 for(int i=1;i<(1<<P);i++) 19 { 20 int ok=1,tem=0; 21 for(int j=1;j<=i;j<<=1) if(i&j) tem++; 22 if(tem>=ans) continue; 23 memset(vis,0,sizeof(vis)); 24 for(int j=1;j<=N;j++) 25 { 26 int cnt=0; 27 for(int k=1;k<=P;k++) 28 if((i&(1<<(k-1)))&&a[j][k]) cnt+=1<<(k-1); 29 if(vis[cnt]) {ok=0;break;} 30 vis[cnt]=1; 31 } 32 if(ok) ans=tem; 33 } 34 printf("%d\n",ans); 35 } 36 return 0; 37 }
HDU 3714 Error Curves
学习了三分的方法。挺好写的。
1 # include <iostream> 2 # include <cstdio> 3 # include <cmath> 4 # include <algorithm> 5 using namespace std; 6 int n,a[10010],b[10010],c[10010]; 7 8 double cal(double x) 9 { 10 double ret=-1e10; 11 for(int i=1;i<=n;i++) 12 { 13 double tem=a[i]*x*x+b[i]*x+c[i]; 14 ret=max(ret,tem); 15 } 16 return ret; 17 } 18 19 int main(void) 20 { 21 int T; cin>>T; 22 while(T--) 23 { 24 scanf("%d",&n); 25 for(int i=1;i<=n;i++) scanf("%d%d%d",a+i,b+i,c+i); 26 double l=0,r=1000,ans; 27 while(1) 28 { 29 double m1=(2*l+r)/3,m2=(l+2*r)/3; 30 double t1=cal(m1),t2=cal(m2); 31 if(fabs(t2-t1)<1e-6) {ans=t1;break;} 32 if(t1>t2) l=m1; 33 else r=m2; 34 } 35 printf("%.4lf\n",ans); 36 } 37 return 0; 38 }
HDU 1172 猜数字
暴力举四位数。当且仅当只有一个数字符合条件的时候有解。
判断的时候注意不要计重了。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 int a[101],b[101],c[101]; 5 6 int main(void) 7 { 8 int N; 9 while(~scanf("%d",&N)&&N) 10 { 11 for(int i=1;i<=N;i++) scanf("%d%d%d",a+i,b+i,c+i); 12 int ans=0; 13 for(int i=1000;i<=9999;i++) 14 { 15 int d1[4],d2[4]; 16 d1[3]=i; 17 for(int j=2;j>=0;j--) 18 { 19 d1[j]=d1[j+1]/10; 20 d1[j+1]-=10*d1[j]; 21 } 22 int flag=1; 23 for(int j=1;j<=N;j++) 24 { 25 d2[3]=a[j]; 26 for(int k=2;k>=0;k--) 27 { 28 d2[k]=d2[k+1]/10; 29 d2[k+1]-=10*d2[k]; 30 } 31 int temb=0,temc=0; 32 for(int k=0;k<4;k++) 33 if(d1[k]==d2[k]) temc++; 34 for(int k=0;k<4;k++) 35 for(int l=0;l<4;l++) 36 if(d1[k]==d2[l]) 37 {d2[l]=-1;temb++;break;} 38 if(temb!=b[j]||temc!=c[j]) {flag=0;break;} 39 } 40 if(flag) 41 { 42 if(ans) {ans=0;break;} 43 else ans=i; 44 } 45 } 46 if(ans) printf("%d\n",ans); 47 else puts("Not sure"); 48 } 49 return 0; 50 }
CF 276D Little Girl and Maximum XOR
神奇。找a和b最高不同位即可。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 typedef long long LL; 5 6 int main(void) 7 { 8 LL a,b; 9 scanf("%I64d%I64d",&a,&b); 10 LL cnt=0,x=a^b; 11 while(x){cnt++; x>>=1;} 12 printf("%I64d\n",((LL)1<<cnt)-1); 13 return 0; 14 }
HDU 1045 Fire Net
dfs水果。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 char map[5][5]; 5 int n,ans,tem; 6 7 void dfs(int x,int y) 8 { 9 if(map[x][y]=='.') 10 { 11 int l=1,r=1,u=1,d=1; 12 for(int i=1;i<x;i++) 13 { 14 if(map[i][y]=='@') u=0; 15 if(map[i][y]=='X') u=1; 16 } 17 for(int i=n;i>x;i--) 18 { 19 if(map[i][y]=='@') d=0; 20 if(map[i][y]=='X') d=1; 21 } 22 for(int i=1;i<y;i++) 23 { 24 if(map[x][i]=='@') l=0; 25 if(map[x][i]=='X') l=1; 26 } 27 for(int i=n;i>y;i--) 28 { 29 if(map[x][i]=='@') r=0; 30 if(map[x][i]=='X') r=1; 31 } 32 if(u&&d&&l&&r) 33 { 34 map[x][y]='@'; tem++; 35 ans=max(ans,tem); 36 if(x<n||y<n)dfs(x+(y+1>n?1:0),y+1>n?1:y+1); 37 map[x][y]='.'; tem--; 38 } 39 } 40 if(x<n||y<n) dfs(x+(y+1>n?1:0),y+1>n?1:y+1); 41 return; 42 } 43 44 int main(void) 45 { 46 while(~scanf("%d",&n)&&n) 47 { 48 for(int i=1;i<=n;i++) 49 scanf("%s",map[i]+1); 50 tem=ans=0; 51 dfs(1,1); 52 printf("%d\n",ans); 53 } 54 return 0; 55 }
CF 433B Kolya and Tandem Repeat
暴力水果。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char s[222]; 6 7 int main(void) 8 { 9 scanf("%s",s+1); 10 int k; scanf("%d",&k); 11 int len=strlen(s+1); 12 for(int i=(len+k)/2;i>=0;i--) 13 { 14 int flag; 15 for(int j=1;j+2*i-1<=len+k;j++) 16 { 17 flag=1; 18 for(int k=j;k<j+i;k++) 19 if(k<=len&&k+i<=len&&s[k]!=s[k+i]) 20 {flag=0;break;} 21 if(flag) break; 22 } 23 if(flag) {printf("%d\n",2*i);break;} 24 } 25 return 0; 26 }
8.24
CF 193B Xor
暴搜。
一个剪枝是连续偶数次xor相当于没做。直接跳过。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 using namespace std; 6 typedef long long LL; 7 const LL INF=(LL)1e18; 8 LL ans,a[40],b[40],k[40],p[40],cur[40]; 9 int n,u,r; 10 11 LL cal(void) 12 { 13 LL ret=0; 14 for(int i=1;i<=n;i++) ret+=cur[i]*k[i]; 15 return ret; 16 } 17 18 void dfs(int step,int op) 19 { 20 if(step==u){ans=max(ans,cal());return;} 21 else if((u-step)%2==0) ans=max(ans,cal()); 22 LL t[40]; 23 for(int i=1;i<=n;i++) t[i]=cur[p[i]]+r; 24 if(op==2) 25 { 26 for(int i=1;i<=n;i++) cur[i]^=b[i]; 27 dfs(step+1,1); 28 } 29 memcpy(cur,t,sizeof(cur)); 30 dfs(step+1,2); 31 return; 32 } 33 34 int main(void) 35 { 36 scanf("%d%d%d",&n,&u,&r); 37 for(int i=1;i<=n;i++) scanf("%I64d",a+i); 38 for(int i=1;i<=n;i++) scanf("%I64d",b+i); 39 for(int i=1;i<=n;i++) scanf("%I64d",k+i); 40 for(int i=1;i<=n;i++) scanf("%I64d",p+i); 41 memcpy(cur,a,sizeof(cur)); 42 ans=-INF; dfs(0,2); 43 printf("%I64d\n",ans); 44 return 0; 45 }
POJ 1753 Flip Game
和牛牛翻牌子一样。
二进制枚举第一行的情况。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 using namespace std; 6 int step[][2]={{0,1},{0,-1},{1,0},{-1,0}}; 7 int org[5][5],map[5][5],ans; 8 9 bool in(int i,int j) 10 { 11 return i&&i<5&&j&&j<5; 12 } 13 14 void Flip(int x,int y) 15 { 16 map[x][y]=1-map[x][y]; 17 for(int i=0;i<4;i++) 18 { 19 int xx=x+step[i][0],yy=y+step[i][1]; 20 if(in(xx,yy)) map[xx][yy]=1-map[xx][yy]; 21 } 22 return; 23 } 24 25 void judge(int i,int c) 26 { 27 memcpy(map,org,sizeof(map)); 28 int cnt=0; 29 for(int j=0;j<4;j++) 30 if((1<<j)&i) {Flip(1,j+1);cnt++;} 31 for(int j=2;j<=4;j++) 32 for(int k=1;k<=4;k++) 33 if(map[j-1][k]!=c) {Flip(j,k);cnt++;} 34 int ok=1; 35 for(int j=1;j<=4;j++) if(map[4][j]!=c) {ok=0;break;} 36 if(ok) ans=min(ans,cnt); 37 return; 38 } 39 40 int main(void) 41 { 42 for(int i=1;i<=4;i++) 43 { 44 char s[10]; 45 scanf("%s",s+1); 46 for(int j=1;j<=4;j++) 47 org[i][j]=(s[j]=='b')?1:0; 48 } 49 ans=20; 50 for(int i=0;i<16;i++) 51 { 52 judge(i,0); 53 judge(i,1); 54 } 55 if(ans<20) printf("%d\n",ans); 56 else puts("Impossible"); 57 return 0; 58 }
CF 442A Borya and Hanabi
神奇方法。
把牌看成二维点。
枚举所有hint的可能。
每一个hint加一条线。
先去掉在交点处的点。再去掉一条直线上唯一的点。
最后如果剩余1个或者不剩余就可行。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <set> 6 using namespace std; 7 typedef pair<int,int> pii; 8 int map[6][6],cpy[6][6],mark[6]; 9 char alp[]=" RGBYW"; 10 set<pii> S,tem; 11 12 int id(char c) 13 { 14 for(int i=1;i<=5;i++) if(c==alp[i]) return i; 15 } 16 17 int main(void) 18 { 19 int n; scanf("%d",&n); 20 for(int i=1;i<=n;i++) 21 { 22 char s[5]; scanf("%s",s); 23 int a=id(s[0]),b=s[1]-'0'; 24 S.insert(pii(a,b)); 25 map[a][b]=1; 26 } 27 int ans=10; 28 for(int i=0;i<(1<<5);i++) 29 { 30 for(int j=0;j<(1<<5);j++) 31 { 32 int num=0; tem=S; 33 for(int k=1;k<(1<<5);k<<=1) num+=(k&i?1:0)+(k&j?1:0); 34 if(num>=ans) continue; 35 memset(mark,0,sizeof(mark)); 36 memcpy(cpy,map,sizeof(map)); 37 for(int k=1;k<=5;k++) if((1<<(k-1))&i) mark[k]=1; 38 for(int k=1;k<=5;k++) if((1<<(k-1))&j) 39 { 40 for(int l=1;l<=5;l++) if(mark[l]&&cpy[l][k]) 41 { 42 cpy[l][k]=0; 43 tem.erase(pii(l,k)); 44 } 45 int cnt=0,pos; 46 for(int l=1;l<=5;l++) if(cpy[l][k]) {cnt++;pos=l;} 47 if(cnt==1) 48 { 49 cpy[pos][k]=0; 50 tem.erase(pii(pos,k)); 51 } 52 } 53 for(int k=1;k<=5;k++) if(mark[k]) 54 { 55 int cnt=0,pos; 56 for(int l=1;l<=5;l++) if(cpy[k][l]) {cnt++;pos=l;} 57 if(cnt==1) 58 { 59 cpy[k][pos]=0; 60 tem.erase(pii(k,pos)); 61 } 62 } 63 if(tem.size()<=1) ans=min(ans,num); 64 } 65 } 66 printf("%d\n",ans); 67 return 0; 68 }
CF 430B Balls Game
枚举起点。模拟祖玛。
1 # include <iostream> 2 # include <cstdio> 3 # include <algorithm> 4 using namespace std; 5 int c[101]; 6 7 int main(void) 8 { 9 int n,k,x,ans=0; 10 scanf("%d%d%d",&n,&k,&x); 11 for(int i=1;i<=n;i++) scanf("%d",c+i); 12 for(int i=1;i<n;i++) 13 { 14 if(c[i-1]!=x&&c[i]==x&&c[i+1]==x) 15 { 16 int l=i-1,r=i+2; 17 while(l>0&&r<=n) 18 { 19 if(c[l]!=c[r]) break; 20 int cur=c[l]; 21 if(l>1&&c[l-1]==cur||r<n&&c[r+1]==cur) 22 { 23 while(c[r]==cur) r++; 24 while(c[l]==cur) l--; 25 } 26 else break; 27 } 28 ans=max(ans,r-l-1); 29 } 30 } 31 printf("%d\n",ans); 32 return 0; 33 }
HDU 4717 The Moving Points
因为昨天刚做了个三分印象深刻。于是三分水果。
1 # include <iostream> 2 # include <cstdio> 3 # include <cmath> 4 # include <algorithm> 5 using namespace std; 6 int n; 7 8 struct point 9 { 10 int x,y,vx,vy; 11 double xx,yy; 12 }p[301]; 13 14 double dis(int i,int j) 15 { 16 return sqrt(pow(p[i].xx-p[j].xx,2)+pow(p[i].yy-p[j].yy,2)); 17 } 18 19 double cal(double t) 20 { 21 for(int i=1;i<=n;i++) 22 { 23 p[i].xx=p[i].x+p[i].vx*t; 24 p[i].yy=p[i].y+p[i].vy*t; 25 } 26 double ret=0; 27 for(int i=1;i<=n;i++) 28 for(int j=1;j<=n;j++) 29 ret=max(ret,dis(i,j)); 30 return ret; 31 } 32 33 int main(void) 34 { 35 int T;cin>>T; 36 for(int kase=1;kase<=T;kase++) 37 { 38 scanf("%d",&n); 39 for(int i=1;i<=n;i++) 40 scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].vx,&p[i].vy); 41 double l=0,r=1000000000,ans; 42 while(r-l>1e-5) 43 { 44 double m1=(2*l+r)/3,m2=(l+2*r)/3; 45 double t1=cal(m1),t2=cal(m2); 46 if(t1<t2) r=m2; 47 else l=m1; 48 ans=t1; 49 } 50 printf("Case #%d: %.2lf %.2lf\n",kase,l,ans); 51 } 52 return 0; 53 }
POJ 2965 The Pilots Brothers' refrigerator
首先每个格子最多翻一次。翻偶数次相当于不翻。奇数次相当于翻一次。
如果要让一个格子(i,j)翻。其他格子不动。只要翻(i,j)后再翻一遍行标为i的其他格子与列标为j的其他格子。
这样只要处理每个-格子。做上面的操作。统计每个格子最后翻的次数奇偶即可。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 int map[6][6]; 5 6 int main(void) 7 { 8 for(int i=1;i<=4;i++) 9 { 10 char s[10]; scanf("%s",s+1); 11 for(int j=1;j<=4;j++) if(s[j]=='+') 12 { 13 for(int k=1;k<=4;k++) map[i][k]++; 14 for(int k=1;k<=4;k++) map[k][j]++; 15 map[i][j]--; 16 } 17 } 18 int ans=0; 19 for(int i=1;i<=4;i++) 20 for(int j=1;j<=4;j++) 21 if(map[i][j]%2) ans++; 22 printf("%d\n",ans); 23 for(int i=1;i<=4;i++) 24 for(int j=1;j<=4;j++) 25 if(map[i][j]%2) 26 printf("%d %d\n",i,j); 27 return 0; 28 }
ZOJ 1008 Gnome Tetravex
直接暴力T。
偷看题解一个优化。把相同的块合在一起就可以了。
表示不服。毕竟块有10000种。而每个图最多只有25个块。
IO挺恶心还PE了两发才过。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 int n,cur,squ[26][4],map[6][6],cnt[26]; 6 7 bool dfs(int x,int y) 8 { 9 if(x>n) return true; 10 for(int i=1;i<=n*n;i++) if(cnt[i]) 11 { 12 if(x>1&&squ[map[x-1][y]][2]!=squ[i][0]) continue; 13 if(y>1&&squ[map[x][y-1]][1]!=squ[i][3]) continue; 14 map[x][y]=i; cnt[i]--; 15 if(dfs(x+(y+1>n?1:0),y+1>n?1:y+1)) return true; 16 map[x][y]=0; cnt[i]++; 17 } 18 return false; 19 } 20 21 int main(void) 22 { 23 int kase=0; 24 while(~scanf("%d",&n)&&n) 25 { 26 memset(cnt,0,sizeof(cnt)); 27 cur=0; 28 for(int i=1;i<=n*n;i++) 29 { 30 int u,r,d,l,same=0; 31 scanf("%d%d%d%d",&u,&r,&d,&l); 32 for(int j=1;j<=cur;j++) 33 if(squ[j][0]==u&&squ[j][1]==r&&squ[j][2]==d&&squ[j][3]==l) 34 {cnt[j]++;same=1;} 35 if(same) continue; 36 cur++; cnt[cur]=1; 37 squ[cur][0]=u; squ[cur][1]=r; squ[cur][2]=d; squ[cur][3]=l; 38 } 39 if(kase) puts(""); 40 printf("Game %d: ",++kase); 41 puts(dfs(1,1)?"Possible":"Impossible"); 42 } 43 return 0; 44 }
找的两份暴力菜切完了。换换口味。回校前学点新东西。
8.25
看KMP。
8.26
HDU 1711 Number Sequence
已经无力吐槽了。贴板。
1 # include <iostream> 2 # include <cstdio> 3 using namespace std; 4 int a[1000100],b[10100]; 5 int n,m,Next[10100]; 6 7 void getNext(void) 8 { 9 Next[0]=Next[1]=0; 10 for(int i=1;i<m;i++) 11 { 12 int j=Next[i]; 13 while(j&&b[i]!=b[j]) j=Next[j]; 14 Next[i+1]=b[i]==b[j]?j+1:0; 15 } 16 return; 17 } 18 19 bool KMP(void) 20 { 21 getNext(); 22 int j=0; 23 for(int i=0;i<n;i++) 24 { 25 while(j&&b[j]!=a[i]) j=Next[j]; 26 if(b[j]==a[i]) j++; 27 if(j==m) {printf("%d\n",i-m+2);return true;} 28 } 29 return false; 30 } 31 32 int main(void) 33 { 34 int T;cin>>T; 35 while(T--) 36 { 37 scanf("%d%d",&n,&m); 38 for(int i=0;i<n;i++) scanf("%d",a+i); 39 for(int i=0;i<m;i++) scanf("%d",b+i); 40 if(KMP()) continue; 41 printf("-1\n"); 42 } 43 return 0; 44 }
抄了个拓展KMP板。没找到验板题。拿上面那题小测好了。
1 # include <iostream> 2 # include <cstdio> 3 # include <algorithm> 4 using namespace std; 5 int a[1000100],ex[1000100]; 6 int b[10100],Next[10100]; 7 int n,m; 8 9 void getNext(void) 10 { 11 int P=1,j; Next[0]=m; 12 for(int i=Next[1]=0;i<m-1&&b[i]==b[i+1];) Next[1]=++i; 13 for(int i=2;i<m;i++) 14 { 15 if(Next[i-P]+i<Next[P]+P) Next[i]=Next[i-P]; 16 else 17 { 18 j=max(Next[P]+P-i,0); 19 while(i+j<m&&b[j]==b[j+i]) j++; 20 Next[i]=j; P=i; 21 } 22 } 23 return; 24 } 25 26 void exKMP(void) 27 { 28 getNext(); 29 int j,P=0; 30 for(int i=ex[0]=0;i<m&&a[i]==b[i];) ex[0]=++i; 31 for(int i=1;i<n;i++) 32 { 33 if(Next[i-P]+i<ex[P]+P) ex[i]=Next[i-P]; 34 else 35 { 36 j=max(ex[P]+P-i,0); 37 while(i+j<n&&j<m&&a[j+i]==b[j]) j++; 38 ex[i]=j; P=i; 39 } 40 } 41 return; 42 } 43 44 int main(void) 45 { 46 int T; cin>>T; 47 while(T--) 48 { 49 scanf("%d%d",&n,&m); 50 for(int i=0;i<n;i++) scanf("%d",a+i); 51 for(int i=0;i<m;i++) scanf("%d",b+i); 52 exKMP(); 53 int ok=0; 54 for(int i=0;i<n;i++) 55 if(ex[i]==m) {printf("%d\n",i+1);ok=1;break;} 56 if(!ok) puts("-1"); 57 } 58 return 0; 59 }
HDU 1686 Oulipo
又一裸KMP。然而完成一次匹配后要滑回Next[j]。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char a[1000100],b[1000100]; 6 int n,m,ans,Next[1000100]; 7 8 void getNext(void) 9 { 10 Next[0]=Next[1]=0; 11 for(int i=1;i<m;i++) 12 { 13 int j=Next[i]; 14 while(j&&b[i]!=b[j]) j=Next[j]; 15 Next[i+1]=b[i]==b[j]?j+1:0; 16 } 17 return; 18 } 19 20 void KMP(void) 21 { 22 getNext(); 23 int j=0; 24 for(int i=0;i<n;i++) 25 { 26 while(j&&b[j]!=a[i]) j=Next[j]; 27 if(b[j]==a[i]) j++; 28 if(j==m) {ans++;j=Next[j];} 29 } 30 return; 31 } 32 33 int main(void) 34 { 35 int T;cin>>T; 36 while(T--) 37 { 38 scanf("%s%s",b,a); 39 m=strlen(b),n=strlen(a); 40 ans=0; KMP(); 41 printf("%d\n",ans); 42 } 43 return 0; 44 }
8.27
HDU 2087 剪花布条
裸KMP。与上题区分。匹配完j重置0。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char a[1000100],b[1000100]; 6 int n,m,ans,Next[1000100]; 7 8 void getNext(void) 9 { 10 Next[0]=Next[1]=0; 11 for(int i=1;i<m;i++) 12 { 13 int j=Next[i]; 14 while(j&&b[i]!=b[j]) j=Next[j]; 15 Next[i+1]=b[i]==b[j]?j+1:0; 16 } 17 return; 18 } 19 20 void KMP(void) 21 { 22 getNext(); 23 int j=0; 24 for(int i=0;i<n;i++) 25 { 26 while(j&&b[j]!=a[i]) j=Next[j]; 27 if(b[j]==a[i]) j++; 28 if(j==m) {ans++;j=0;} 29 } 30 return; 31 } 32 33 int main(void) 34 { 35 while(~scanf("%s",a)) 36 { 37 if(a[0]=='#') break; 38 scanf("%s",b); 39 m=strlen(b),n=strlen(a); 40 ans=0; KMP(); 41 printf("%d\n",ans); 42 } 43 return 0; 44 }
由于不放心。重新抄了套MP/KMP板。
MP板和之前的除了Next[0]=-1其余都一样。
KMP板在速度上并没感觉快。性质反而丢失了。
1 void mp_Next(void) 2 { 3 int i=0,j=Next[0]=-1; 4 while(i<m) 5 { 6 while(-1!=j&&b[i]!=b[j])j=Next[j]; 7 Next[++i]=++j; 8 } 9 return; 10 } 11 12 void kmp_Next(void) 13 { 14 int i=0,j=Next[0]=-1; 15 while(i<m) 16 { 17 while(-1!=j&&b[i]!=b[j])j=Next[j]; 18 if(b[++i]==b[++j]) Next[i]=Next[j]; 19 else Next[i]=j; 20 } 21 return; 22 } 23 24 void KMP(void) 25 { 26 int i=0,j=0; 27 mp_Next(); 28 while(i<n) 29 { 30 while(-1!=j&&a[i]!=b[j])j=Next[j]; 31 i++;j++; 32 if(j==m){/*爱干嘛干嘛*/} 33 } 34 return; 35 }
HDU 3746 Cyclic Nacklace
运用了Next数组的一个性质。
可以求循环节。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char b[100100]; 6 int m,Next[100100]; 7 8 void getNext(void) 9 { 10 Next[0]=Next[1]=0; 11 for(int i=1;i<m;i++) 12 { 13 int j=Next[i]; 14 while(j&&b[i]!=b[j]) j=Next[j]; 15 Next[i+1]=b[i]==b[j]?j+1:0; 16 } 17 return; 18 } 19 20 int main(void) 21 { 22 int T; cin>>T; 23 while(T--) 24 { 25 scanf("%s",b); 26 m=strlen(b); 27 getNext(); 28 int t=m-Next[m]; 29 if(t!=m&&m%t==0)printf("0\n"); 30 else printf("%d\n",t-m%t); 31 } 32 return 0; 33 }
HDU 1358 Period
题意:求能分解成循环的前缀。
学了上面的性质就很好做了。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char b[1000100]; 6 int m,Next[1000100]; 7 8 void getNext(void) 9 { 10 Next[0]=Next[1]=0; 11 for(int i=1;i<m;i++) 12 { 13 int j=Next[i]; 14 while(j&&b[i]!=b[j]) j=Next[j]; 15 Next[i+1]=b[i]==b[j]?j+1:0; 16 } 17 return; 18 } 19 20 int main(void) 21 { 22 int kase=0; 23 while(~scanf("%d",&m)&&m) 24 { 25 scanf("%s",b); 26 getNext(); 27 printf("Test case #%d\n",++kase); 28 for(int i=1;i<=m;i++) 29 { 30 int t=i-Next[i]; 31 if(i%t==0&&i/t>1) printf("%d %d\n",i,i/t); 32 } 33 puts(""); 34 } 35 return 0; 36 }
HUST 1010 The Minimum Length
从后往前找第一个完整循环的循序节就是答案。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char b[1000100]; 6 int m,Next[1000100]; 7 8 void getNext(void) 9 { 10 Next[0]=Next[1]=0; 11 for(int i=1;i<m;i++) 12 { 13 int j=Next[i]; 14 while(j&&b[i]!=b[j]) j=Next[j]; 15 Next[i+1]=b[i]==b[j]?j+1:0; 16 } 17 return; 18 } 19 20 int main(void) 21 { 22 while(~scanf("%s",&b)) 23 { 24 m=strlen(b); 25 getNext(); 26 for(int i=m;;i--) 27 { 28 int t=i-Next[i]; 29 if(i%t==0) {printf("%d\n",t);break;} 30 } 31 } 32 return 0; 33 }
POJ 2406 Power Strings
能拆成小循环就拆。不能就是1。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char b[1000100]; 6 int m,Next[1000100]; 7 8 void getNext(void) 9 { 10 Next[0]=Next[1]=0; 11 for(int i=1;i<m;i++) 12 { 13 int j=Next[i]; 14 while(j&&b[i]!=b[j]) j=Next[j]; 15 Next[i+1]=b[i]==b[j]?j+1:0; 16 } 17 return; 18 } 19 20 int main(void) 21 { 22 while(~scanf("%s",&b)) 23 { 24 if(b[0]=='.') break; 25 m=strlen(b); 26 getNext(); 27 int t=m-Next[m]; 28 if(m%t!=0) puts("1"); 29 else printf("%d\n",m/t); 30 } 31 return 0; 32 }
POJ 2752 Seek the Name, Seek the Fame
顺Next数组反向找回去。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char b[1000100]; 6 int m,Next[1000100]; 7 8 void getNext(void) 9 { 10 Next[0]=Next[1]=0; 11 for(int i=1;i<m;i++) 12 { 13 int j=Next[i]; 14 while(j&&b[i]!=b[j]) j=Next[j]; 15 Next[i+1]=b[i]==b[j]?j+1:0; 16 } 17 return; 18 } 19 20 void ans_print(int pos) 21 { 22 if(Next[pos]) ans_print(Next[pos]); 23 printf("%d ",pos); 24 return; 25 } 26 27 int main(void) 28 { 29 while(~scanf("%s",&b)) 30 { 31 m=strlen(b); 32 getNext(); 33 ans_print(m); 34 puts(""); 35 } 36 return 0; 37 }
POJ 3080 Blue Jeans
因为挂在KMP专题里。所以就暴力水果了?
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 using namespace std; 5 char ans[70],tem[70]; 6 char DNA[20][70]; 7 8 int main(void) 9 { 10 int T ; cin>>T; 11 while(T--) 12 { 13 int n; scanf("%d",&n); 14 memset(ans,0,sizeof(ans)); 15 for(int i=1;i<=n;i++) scanf("%s",DNA[i]+1); 16 int yes=0; 17 for(int l=60;l>2;l--) 18 { 19 for(int s=1;s+l-1<=60;s++) 20 { 21 memcpy(tem,DNA[1]+s,l*sizeof(char)); 22 tem[l]=0; 23 int ok=1; 24 for(int i=2;i<=n;i++) 25 if(!strstr(DNA[i]+1,tem)) 26 {ok=0;break;} 27 if(ok) 28 { 29 yes=1; 30 if(!strlen(ans)||strcmp(ans,tem)>0) 31 strcpy(ans,tem); 32 } 33 } 34 if(yes) {printf("%s\n",ans);break;} 35 } 36 if(!yes) puts("no significant commonalities"); 37 } 38 return 0; 39 }
8.28
HDU 2594 Simpsons’ Hidden Talents
方便的想法是把两串连一起。找前后缀。
1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 using namespace std; 6 char b[100100]; 7 int m,Next[100100]; 8 9 void getNext(void) 10 { 11 Next[0]=Next[1]=0; 12 for(int i=1;i<m;i++) 13 { 14 int j=Next[i]; 15 while(j&&b[i]!=b[j]) j=Next[j]; 16 Next[i+1]=b[i]==b[j]?j+1:0; 17 } 18 return; 19 } 20 21 int main(void) 22 { 23 while(~scanf("%s",&b)) 24 { 25 int n=strlen(b); 26 scanf("%s",b+n); 27 m=strlen(b); 28 getNext(); 29 int ans=m; 30 while(ans>min(m-n,n)) ans=Next[ans]; 31 if(ans) 32 { 33 for(int i=0;i<ans;i++) putchar(b[i]); 34 printf(" "); 35 } 36 printf("%d\n",ans); 37 } 38 return 0; 39 }
8.29
滚回学校。
BC爆。
不补。