2014 ACM/ICPC 北京邀请赛 部分 题解
总共十道题, 又结束了一场逗比的比赛, 感觉后半场都在梦游,结果被虐了!!!!大家都虐我一万里啊。
正如wushen说的,“那些被虐过的比赛,唯有赛后AK掉来泄愤。”
本弱太菜,还达不到AK的境界,只能搞出这场的8道题。
A
A Matrix
一个很神奇的题目,全场就坑在这题了,其实应该画几组去看看的,比较容易发现规律的。
根据规则可以知道,一个数想要往下走一行,必须有个比它小的数在后面插入,把它推下去。
题目要求输出逆序 后 字典序最大的结果。
其实首先要每行是递增的。
然后每一行的数,在上一行找一个比它小,而且没有使用过的。
然后就形成了一颗颗链, 把链输出就是结果了。
也可以使用拓扑排序,结果是一样的。
这题就是要靠智商啊,要锻炼自己YY的能力了。
来代码吧!
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 11:38:45 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\A.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MAXN = 100010; 21 vector<int>vec[MAXN]; 22 int pre[MAXN]; 23 vector<int>ans; 24 void add(int u) 25 { 26 if(u == -1)return ; 27 add(pre[u]); 28 ans.push_back(u); 29 } 30 31 int main() 32 { 33 //freopen("in.txt","r",stdin); 34 //freopen("out.txt","w",stdout); 35 int T; 36 int iCase = 0; 37 scanf("%d",&T); 38 int n,m; 39 while(T--) 40 { 41 iCase++; 42 scanf("%d%d",&n,&m); 43 for(int i = 0;i < m;i++) 44 vec[i].clear(); 45 for(int i = 0;i < m;i++) 46 { 47 int num; 48 int x; 49 scanf("%d",&num); 50 while(num--) 51 { 52 scanf("%d",&x); 53 vec[i].push_back(x); 54 } 55 } 56 bool flag = true; 57 for(int i = 0;i < m;i++) 58 { 59 int sz = vec[i].size(); 60 for(int j = 1;j < sz;j++) 61 if(vec[i][j] < vec[i][j-1]) 62 { 63 flag = false; 64 break; 65 } 66 } 67 if(!flag) 68 { 69 printf("Case #%d: No solution\n",iCase); 70 continue; 71 } 72 memset(pre,-1,sizeof(pre)); 73 for(int i = m-1;i > 0;i--) 74 { 75 int sz = vec[i].size(); 76 int p = vec[i-1].size(); 77 for(int j = sz-1;j >= 0;j--) 78 { 79 if(p <= 0) 80 { 81 flag = false; 82 break; 83 } 84 p = lower_bound(vec[i-1].begin(),vec[i-1].begin()+p,vec[i][j]) - vec[i-1].begin() + 1; 85 p--; 86 if(p <= 0) 87 { 88 flag = false; 89 break; 90 } 91 pre[vec[i-1][p-1]] = vec[i][j]; 92 p--; 93 } 94 } 95 if(!flag) 96 { 97 printf("Case #%d: No solution\n",iCase); 98 continue; 99 } 100 ans.clear(); 101 for(int i = 0;i < vec[0].size();i++) 102 add(vec[0][i]); 103 printf("Case #%d:",iCase); 104 for(int i = 0;i < n;i++) 105 printf(" %d",ans[i]); 106 printf("\n"); 107 } 108 109 return 0; 110 }
B
Beautiful Garden
题目: x轴上有n颗树,要求移动最少树的位置,使得相邻两颗树的距离都一样。
暴力枚举,复杂度是n^4logn的
最后结果肯定有两个树是不动的,然后没有两颗树之间插入几个,就知道公差了,然后去搞。
树可以移动到非整数点,但是好像没有必要,我做的时候是考虑了公差是浮点数啥的。
注意特判n<=2 的时候
代码:
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 12:59:17 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\B.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 long long gcd(long long a,long long b) 21 { 22 if(b == 0)return a; 23 return gcd(b,a%b); 24 } 25 int a[100]; 26 map<long long,int>mp; 27 28 int main() 29 { 30 //freopen("in.txt","r",stdin); 31 //freopen("out.txt","w",stdout); 32 int T; 33 int n; 34 int iCase = 0; 35 scanf("%d",&T); 36 while(T--) 37 { 38 iCase++; 39 scanf("%d",&n); 40 mp.clear(); 41 for(int i = 0;i < n;i++) 42 { 43 scanf("%d",&a[i]); 44 if(mp.find(a[i]) == mp.end())mp[a[i]] = 1; 45 else mp[a[i]]++; 46 } 47 if(n <= 2) 48 { 49 printf("Case #%d: 0\n",iCase); 50 continue; 51 } 52 int ans = n; 53 for(int i = 0;i < n;i++) 54 for(int j = i+1;j < n;j++) 55 { 56 long long d2 = a[i] - a[j]; 57 if(d2 == 0) 58 { 59 ans = min(ans,n - mp[a[i]]); 60 continue; 61 } 62 if(d2 < 0)d2 = -d2; 63 for(int k = 0;k <= n-2;k++) 64 { 65 long long dis = k+1; 66 long long g = gcd(dis,d2); 67 long long d = d2/g; 68 dis /= g; 69 long long c = min(a[i],a[j]); 70 int cnt = 0; 71 for(int x = 0;x < n;x += dis) 72 { 73 if(mp.find(c) != mp.end())cnt++; 74 c += d; 75 } 76 ans = min(ans,n-cnt); 77 } 78 } 79 printf("Case #%d: %d\n",iCase,ans); 80 } 81 return 0; 82 }
C
Champions League
这个题目很暴力。
其实可以发现只有前6大的group是有效的,这个可以反证法去思考下。
然后对于前6大,暴力状态压缩DP下就是答案了,情况不多的,很少。
很黄很暴力啊^_^
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 12:03:28 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\C.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MAXN = 10010; 21 struct Node 22 { 23 int a[4][4]; 24 void input() 25 { 26 for(int i = 0;i < 4;i++) 27 for(int j = 0;j < 4;j++) 28 scanf("%d",&a[i][j]); 29 } 30 int b[12]; 31 void init() 32 { 33 int cnt = 0; 34 for(int i = 0;i < 4;i++) 35 for(int j = 0;j < 4;j++) 36 if(i != j) 37 b[cnt++] = a[i][j]; 38 sort(b,b+cnt); 39 reverse(b,b+cnt); 40 } 41 int c[100];//二进制表示选哪一天的最大值 42 int day[10][4];//每天的组合情况 43 void calc() 44 { 45 for(int i = 0;i < (1<<6);i++) 46 c[i] = 0; 47 int d[7]; 48 for(int d1 = 1;d1 < 4; d1++) 49 for(int d2 = 1; d2 < 4;d2++) 50 if(d1 != d2) 51 for(int k = 0;k < (1<<6);k++) 52 { 53 memset(day,-1,sizeof(day)); 54 day[0][0] = 0; day[0][1] = d1; 55 day[1][0] = 0; day[1][1] = d2; 56 day[2][0] = 0; day[2][1] = 6 - d1 - d2; 57 for(int i = 0;i < 3;i++) 58 for(int j = 0;j < 4;j++) 59 if(j != day[i][0] && j != day[i][1]) 60 { 61 if(day[i][2] == -1)day[i][2] = j; 62 else day[i][3] = j; 63 } 64 if(k & (1<<0))swap(day[0][0],day[0][1]); 65 if(k & (1<<1))swap(day[0][2],day[0][3]); 66 if(k & (1<<2))swap(day[1][0],day[1][1]); 67 if(k & (1<<3))swap(day[1][2],day[1][3]); 68 if(k & (1<<4))swap(day[2][0],day[2][1]); 69 if(k & (1<<5))swap(day[2][2],day[2][3]); 70 for(int i = 3;i < 6;i++) 71 for(int j = 0;j < 4;j++) 72 day[i][j] = day[i-3][j^1]; 73 for(int i = 0;i < 6;i++) 74 d[i] = max(a[day[i][0]][day[i][1]],a[day[i][2]][day[i][3]]); 75 for(int i = 0;i < (1<<6);i++) 76 { 77 int tmp = 0; 78 for(int j = 0;j < 6;j++) 79 if(i & (1<<j)) 80 tmp += d[j]; 81 c[i] = max(c[i],tmp); 82 } 83 } 84 } 85 }node[MAXN]; 86 bool cmp(Node a,Node b) 87 { 88 for(int i = 0;i < 12;i++) 89 { 90 if(a.b[i] > b.b[i])return true; 91 else if(a.b[i] < b.b[i])return false; 92 } 93 return true; 94 } 95 96 int dp[10][100]; 97 int main() 98 { 99 //freopen("in.txt","r",stdin); 100 //freopen("out.txt","w",stdout); 101 int T; 102 int n; 103 int iCase = 0; 104 scanf("%d",&T); 105 while(T--) 106 { 107 iCase++; 108 scanf("%d",&n); 109 for(int i = 0;i < n;i++) 110 node[i].input(); 111 if(n > 6) 112 { 113 for(int i = 0;i < n;i++) 114 node[i].init(); 115 sort(node,node+n,cmp); 116 n = 6; 117 } 118 for(int i = 0;i < n;i++)node[i].calc(); 119 memset(dp,0,sizeof(dp)); 120 for(int i = 1;i <= n;i++) 121 for(int j = 0;j < (1<<6);j++) 122 { 123 for(int k = 0;k < (1<<6);k++) 124 if((j|k) == j) 125 dp[i][j] = max(dp[i][j],dp[i-1][k]+node[i-1].c[j^k]); 126 } 127 printf("Case #%d: %d\n",iCase,dp[n][(1<<6)-1]); 128 } 129 return 0; 130 }
D:
Dices in Yahtzee
这题我现场理解错意思了, 那个最佳策略 其实是不知道结果的,是按照一个个分配的。
然后就很水了,状态压缩下,搞概率DP
裸的话,复杂度是2^14 * 6^5 * 14 有点大。
可以把6^5稍微优化下,排序从小到大。
这题更加暴力了,思路也很简单。
我写成5个循环了,就是要体现暴力性!!
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 23:06:03 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\D.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 double p[6]; 21 22 double pp[6][6][6][6][6]; 23 int s[6][6][6][6][6][14]; 24 bool used[6][6][6][6][6]; 25 void calc(int a,int b,int c,int d,int e,double tp) 26 { 27 int x[6]; 28 x[0] = a; x[1] = b; x[2] = c; x[3] = d; x[4] = e; 29 sort(x,x+5); 30 a = x[0]; b = x[1]; c = x[2]; d = x[3]; e = x[4]; 31 if(used[a][b][c][d][e]) 32 { 33 pp[a][b][c][d][e] += tp; 34 return; 35 } 36 pp[a][b][c][d][e] = tp; 37 used[a][b][c][d][e] = true; 38 39 40 memset(s[a][b][c][d][e],0,sizeof(s[a][b][c][d][e])); 41 for(int i = 0;i < 5;i++) 42 s[a][b][c][d][e][x[i]] += x[i]+1; 43 int sum = a + b + c + d + e + 5; 44 int cnt[6]; 45 for(int i = 0;i < 6;i++)cnt[i] = 0; 46 for(int i = 0;i < 5;i++) 47 cnt[x[i]]++; 48 if( (cnt[0] && cnt[1] && cnt[2] && cnt[3] && cnt[4]) || 49 (cnt[1] && cnt[2] && cnt[3] && cnt[4] && cnt[5]) ) 50 s[a][b][c][d][e][11] = 40; 51 if( (cnt[0] && cnt[1] && cnt[2] && cnt[3]) || 52 (cnt[1] && cnt[2] && cnt[3] && cnt[4]) || 53 (cnt[2] && cnt[3] && cnt[4] && cnt[5]) ) 54 s[a][b][c][d][e][10] = 30; 55 sort(cnt,cnt+6); 56 if(cnt[4] >= 2 && cnt[5] >= 2) 57 s[a][b][c][d][e][6] = sum; 58 if(cnt[5] >= 3) 59 s[a][b][c][d][e][7] = sum; 60 if(cnt[5] >= 4) 61 s[a][b][c][d][e][8] = sum; 62 if(cnt[4] ==2 && cnt[5] == 3) 63 s[a][b][c][d][e][9] = 25; 64 if(cnt[5] == 5) 65 s[a][b][d][d][e][12] = 50; 66 s[a][b][c][d][e][13] = sum; 67 } 68 double dp[(1<<14)+10]; 69 70 int main() 71 { 72 //freopen("in.txt","r",stdin); 73 //freopen("out.txt","w",stdout); 74 int T; 75 int iCase = 0; 76 scanf("%d",&T); 77 while(T--) 78 { 79 iCase++; 80 for(int i = 0;i < 6;i++)scanf("%lf",&p[i]); 81 memset(used,false,sizeof(used)); 82 for(int a = 0;a < 6;a++) 83 for(int b = 0;b < 6;b++) 84 for(int c = 0;c < 6;c++) 85 for(int d = 0;d < 6;d++) 86 for(int e = 0;e < 6;e++) 87 { 88 double tp = p[a]*p[b]*p[c]*p[d]*p[e]; 89 calc(a,b,c,d,e,tp); 90 } 91 dp[(1<<14)-1] = 0.0; 92 for(int i = (1<<14)-2;i >= 0;i--) 93 { 94 dp[i] = 0.0; 95 for(int a = 0;a < 6;a++) 96 for(int b = a;b < 6;b++) 97 for(int c = b;c < 6;c++) 98 for(int d = c;d < 6;d++) 99 for(int e = d;e < 6;e++) 100 { 101 double tmp = 0; 102 for(int j = 0;j < 14;j++) 103 if( (i & (1<<j)) == 0 ) 104 tmp = max(tmp,dp[i|(1<<j)]+s[a][b][c][d][e][j]); 105 dp[i] += tmp * pp[a][b][c][d][e]; 106 } 107 } 108 printf("Case #%d: %.6lf\n",iCase,dp[0]); 109 } 110 return 0; 111 }
E:
Elegant String
写出状态转移方程。
dp[i][j] 表示长度是i, 后面有j个不同。
然后矩阵也很好写了。
注意是要想状态转移方程。
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 13:11:27 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\E.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MOD = 20140518; 21 struct Matrix 22 { 23 int mat[12][12]; 24 int n; 25 void init(int _n) 26 { 27 n = _n; 28 memset(mat,0,sizeof(mat)); 29 } 30 Matrix operator *(const Matrix &b)const 31 { 32 Matrix ret; 33 ret.n = n; 34 for(int i = 0;i < n;i++) 35 for(int j = 0;j < n;j++) 36 { 37 ret.mat[i][j] = 0; 38 for(int k = 0;k < n;k++) 39 { 40 ret.mat[i][j] += (long long)mat[i][k]*b.mat[k][j]%MOD; 41 if(ret.mat[i][j] >= MOD) 42 ret.mat[i][j] -= MOD; 43 } 44 } 45 return ret; 46 } 47 }; 48 Matrix pow_M(Matrix a,long long n) 49 { 50 Matrix ret; 51 ret.init(a.n); 52 for(int i = 0;i < a.n;i++) 53 ret.mat[i][i] = 1; 54 Matrix tmp = a; 55 while(n) 56 { 57 if(n&1)ret = ret*tmp; 58 tmp = tmp*tmp; 59 n >>= 1; 60 } 61 return ret; 62 } 63 64 int main() 65 { 66 //freopen("in.txt","r",stdin); 67 //freopen("out.txt","w",stdout); 68 int T; 69 int k; 70 long long n; 71 scanf("%d",&T); 72 int iCase = 0; 73 while(T--) 74 { 75 iCase++; 76 cin>>n>>k; 77 if(n <= 1) 78 { 79 printf("Case #%d: %d\n",iCase,k+1); 80 continue; 81 } 82 Matrix A; 83 A.init(k); 84 for(int i = 0;i < k;i++) 85 for(int j = 0;j <= i;j++) 86 A.mat[i][j] = 1; 87 for(int i = 0;i < k-1;i++) 88 A.mat[i][i+1] = k - i; 89 A = pow_M(A,n-1); 90 long long ans = 0; 91 for(int i = 0;i < k;i++) 92 { 93 ans += (long long)(k+1)*A.mat[0][i]%MOD; 94 ans %= MOD; 95 } 96 printf("Case #%d: %d\n",iCase,(int)ans); 97 } 98 return 0; 99 }
F:
Football on Table
属于暴力搞过去了,没啥算法。
读懂题就可以了
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 13:50:23 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\F.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const double eps = 1e-8; 21 double a[210]; 22 double b[210]; 23 double suma[210]; 24 double sumb[210]; 25 26 int main() 27 { 28 //freopen("in.txt","r",stdin); 29 //freopen("out.txt","w",stdout); 30 double L,W; 31 int T; 32 int iCase = 0; 33 scanf("%d",&T); 34 while(T--) 35 { 36 iCase++; 37 scanf("%lf%lf",&L,&W); 38 double X,Y,dx,dy; 39 scanf("%lf%lf%lf%lf",&X,&Y,&dx,&dy); 40 int m; 41 scanf("%d",&m); 42 double ans = 1.0; 43 while(m--) 44 { 45 double x; 46 int n; 47 scanf("%lf%d",&x,&n); 48 for(int i = 1;i <= n;i++) 49 scanf("%lf",&a[i]); 50 for(int i = 1;i < n;i++) 51 scanf("%lf",&b[i]); 52 if(x <= X) 53 continue; 54 double y = Y + (x - X)*dy/dx; 55 suma[0] = 0.0; 56 for(int i = 1;i <= n;i++) 57 suma[i] = suma[i-1] + a[i]; 58 sumb[0] = 0.0; 59 for(int i = 1;i < n;i++) 60 sumb[i] = sumb[i-1] + b[i]; 61 double LL = W - suma[n] - sumb[n-1]; 62 double tmp = 0; 63 for(int i = 0;i <= n;i++) 64 { 65 double down,up; 66 if(i == 0) 67 { 68 down = y; 69 up = LL; 70 } 71 else if(i == n) 72 { 73 down = 0; 74 up = y - suma[n] - sumb[n-1]; 75 } 76 else 77 { 78 down = max(0.0,y - suma[i] - sumb[i]); 79 up = min(LL,y - suma[i] - sumb[i-1]); 80 } 81 if(up > down)tmp += up - down; 82 } 83 ans *= tmp/LL; 84 } 85 printf("Case #%d: %.5lf\n",iCase,ans); 86 } 87 return 0; 88 }
G
Great Escape
不会,(*^__^*) 貌似利用凸性吧, 在弥补中
H:
Happy Reversal
一前一后预处理下,很水。
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 13:23:41 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\H.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 21 long long two[100]; 22 long long a[10010]; 23 long long b[10010]; 24 long long c[10010]; 25 long long d[10010]; 26 char str[200]; 27 28 int main() 29 { 30 //freopen("in.txt","r",stdin); 31 //freopen("out.txt","w",stdout); 32 two[0] = 1; 33 for(int i = 1;i < 63;i++) 34 two[i] = 2*two[i-1]; 35 int T; 36 int iCase = 0; 37 int n,k; 38 scanf("%d",&T); 39 while(T--) 40 { 41 iCase++; 42 scanf("%d%d",&n,&k); 43 for(int i = 1;i <= n;i++) 44 { 45 scanf("%s",str); 46 a[i] = b[i] = 0; 47 for(int j = 0;j < k;j++) 48 { 49 if(str[j] == '0')a[i] += two[k-j-1]; 50 else b[i] += two[k-j-1]; 51 } 52 } 53 if(n <= 1) 54 { 55 printf("Case #%d: 0\n",iCase); 56 continue; 57 } 58 c[1] = min(a[1],b[1]); 59 for(int i = 2;i <= n;i++) 60 { 61 c[i] = min(a[i],b[i]); 62 c[i] = min(c[i],c[i-1]); 63 } 64 d[n] = min(a[n],b[n]); 65 for(int i = n-1;i >= 1;i--) 66 { 67 d[i] = min(a[i],b[i]); 68 d[i] = min(d[i],d[i+1]); 69 } 70 long long ans = 0; 71 for(int i = 1;i <= n;i++) 72 { 73 long long tmp1 = max(a[i],b[i]); 74 long long tmp2 ; 75 if(i == 1)tmp2 = d[i+1]; 76 else if(i == n)tmp2 = c[i-1]; 77 else tmp2 = min(c[i-1],d[i+1]); 78 ans = max(ans,tmp1-tmp2); 79 } 80 printf("Case #%d: %lld\n",iCase,ans); 81 } 82 return 0; 83 }
I:
In A Maze
神几何,还不会
J:
Justice String
可以使用后缀数组,求lcp, 然后最多枚举,最多匹配三次。
或者使用exkmp, 前后求lcp,中间hash判断相等。
现场没有卡nlogn的SA, 重现时候用O(n)的SA才过
1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2014/5/21 13:35:56 4 File Name :E:\2014ACM\比赛\2014北京邀请赛\J.cpp 5 ************************************************ */ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <iostream> 10 #include <algorithm> 11 #include <vector> 12 #include <queue> 13 #include <set> 14 #include <map> 15 #include <string> 16 #include <math.h> 17 #include <stdlib.h> 18 #include <time.h> 19 using namespace std; 20 const int MAXN=600010; 21 /* 22 int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值 23 //待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m, 24 //除s[n-1]外的所有s[i]都大于0,r[n-1]=0 25 //函数结束以后结果放在sa数组中 26 bool cmp(int *r,int a,int b,int l) 27 { 28 return r[a] == r[b] && r[a+l] == r[b+l]; 29 } 30 void da(int str[],int sa[],int rank[],int height[],int n,int m) 31 { 32 n++; 33 int i, j, p, *x = t1, *y = t2; 34 //第一轮基数排序,如果s的最大值很大,可改为快速排序 35 for(i = 0;i < m;i++)c[i] = 0; 36 for(i = 0;i < n;i++)c[x[i] = str[i]]++; 37 for(i = 1;i < m;i++)c[i] += c[i-1]; 38 for(i = n-1;i >= 0;i--)sa[--c[x[i]]] = i; 39 for(j = 1;j <= n; j <<= 1) 40 { 41 p = 0; 42 //直接利用sa数组排序第二关键字 43 for(i = n-j; i < n; i++)y[p++] = i;//后面的j个数第二关键字为空的最小 44 for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j; 45 //这样数组y保存的就是按照第二关键字排序的结果 46 //基数排序第一关键字 47 for(i = 0; i < m; i++)c[i] = 0; 48 for(i = 0; i < n; i++)c[x[y[i]]]++; 49 for(i = 1; i < m;i++)c[i] += c[i-1]; 50 for(i = n-1; i >= 0;i--)sa[--c[x[y[i]]]] = y[i]; 51 //根据sa和x数组计算新的x数组 52 swap(x,y); 53 p = 1; x[sa[0]] = 0; 54 for(i = 1;i < n;i++) 55 x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++; 56 if(p >= n)break; 57 m = p;//下次基数排序的最大值 58 } 59 int k = 0; 60 n--; 61 for(i = 0;i <= n;i++)rank[sa[i]] = i; 62 for(i = 0;i < n;i++) 63 { 64 if(k)k--; 65 j = sa[rank[i]-1]; 66 while(str[i+k] == str[j+k])k++; 67 height[rank[i]] = k; 68 } 69 } 70 */ 71 /* 72 * 后缀数组 73 * DC3算法,复杂度O(n) 74 * 所有的相关数组都要开三倍 75 */ 76 #define F(x) ((x)/3+((x)%3==1?0:tb)) 77 #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) 78 int wa[MAXN*3],wb[MAXN*3],wv[MAXN*3],wss[MAXN*3]; 79 int c0(int *r,int a,int b) 80 { 81 return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2]; 82 } 83 int c12(int k,int *r,int a,int b) 84 { 85 if(k == 2) 86 return r[a] < r[b] || ( r[a] == r[b] && c12(1,r,a+1,b+1) ); 87 else return r[a] < r[b] || ( r[a] == r[b] && wv[a+1] < wv[b+1] ); 88 } 89 void sort(int *r,int *a,int *b,int n,int m) 90 { 91 int i; 92 for(i = 0;i < n;i++)wv[i] = r[a[i]]; 93 for(i = 0;i < m;i++)wss[i] = 0; 94 for(i = 0;i < n;i++)wss[wv[i]]++; 95 for(i = 1;i < m;i++)wss[i] += wss[i-1]; 96 for(i = n-1;i >= 0;i--) 97 b[--wss[wv[i]]] = a[i]; 98 } 99 void dc3(int *r,int *sa,int n,int m) 100 { 101 int i, j, *rn = r + n; 102 int *san = sa + n, ta = 0, tb = (n+1)/3, tbc = 0, p; 103 r[n] = r[n+1] = 0; 104 for(i = 0;i < n;i++)if(i %3 != 0)wa[tbc++] = i; 105 sort(r + 2, wa, wb, tbc, m); 106 sort(r + 1, wb, wa, tbc, m); 107 sort(r, wa, wb, tbc, m); 108 for(p = 1, rn[F(wb[0])] = 0, i = 1;i < tbc;i++) 109 rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++; 110 if(p < tbc)dc3(rn,san,tbc,p); 111 else for(i = 0;i < tbc;i++)san[rn[i]] = i; 112 for(i = 0;i < tbc;i++) if(san[i] < tb)wb[ta++] = san[i] * 3; 113 if(n % 3 == 1)wb[ta++] = n - 1; 114 sort(r, wb, wa, ta, m); 115 for(i = 0;i < tbc;i++)wv[wb[i] = G(san[i])] = i; 116 for(i = 0, j = 0, p = 0;i < ta && j < tbc;p++) 117 sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++]; 118 for(;i < ta;p++)sa[p] = wa[i++]; 119 for(;j < tbc;p++)sa[p] = wb[j++]; 120 } 121 //str和sa也要三倍 122 void da(int str[],int sa[],int rank[],int height[],int n,int m) 123 { 124 for(int i = n;i < n*3;i++) 125 str[i] = 0; 126 dc3(str, sa, n+1, m); 127 int i,j,k = 0; 128 for(i = 0;i <= n;i++)rank[sa[i]] = i; 129 for(i = 0;i < n; i++) 130 { 131 if(k) k--; 132 j = sa[rank[i]-1]; 133 while(str[i+k] == str[j+k]) k++; 134 height[rank[i]] = k; 135 } 136 } 137 138 139 int rank[MAXN],height[MAXN]; 140 int RMQ[MAXN]; 141 int mm[MAXN]; 142 int best[20][MAXN]; 143 void initRMQ(int n) 144 { 145 mm[0]=-1; 146 for(int i=1;i<=n;i++) 147 mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; 148 for(int i=1;i<=n;i++)best[0][i]=i; 149 for(int i=1;i<=mm[n];i++) 150 for(int j=1;j+(1<<i)-1<=n;j++) 151 { 152 int a=best[i-1][j]; 153 int b=best[i-1][j+(1<<(i-1))]; 154 if(RMQ[a]<RMQ[b])best[i][j]=a; 155 else best[i][j]=b; 156 } 157 } 158 int askRMQ(int a,int b) 159 { 160 int t; 161 t=mm[b-a+1]; 162 b-=(1<<t)-1; 163 a=best[t][a];b=best[t][b]; 164 return RMQ[a]<RMQ[b]?a:b; 165 } 166 int lcp(int a,int b) 167 { 168 a=rank[a];b=rank[b]; 169 if(a>b)swap(a,b); 170 return height[askRMQ(a+1,b)]; 171 } 172 char A[MAXN],B[MAXN]; 173 int r[MAXN]; 174 int sa[MAXN]; 175 176 int main() 177 { 178 //freopen("in.txt","r",stdin); 179 //freopen("out.txt","w",stdout); 180 int T; 181 int iCase = 0; 182 scanf("%d",&T); 183 while(T--) 184 { 185 iCase++; 186 scanf("%s%s",A,B); 187 int len1 = strlen(A); 188 int len2 = strlen(B); 189 if(len1 < len2) 190 { 191 printf("Case #%d: -1\n",iCase); 192 continue; 193 } 194 int n = len1+len2+1; 195 for(int i = 0;i < len1;i++)r[i] = A[i]; 196 for(int i = 0;i < len2;i++)r[len1+1+i] = B[i]; 197 r[len1] = 1; 198 r[n] = 0; 199 da(r,sa,rank,height,n,128); 200 for(int i = 1;i <= n;i++)RMQ[i] = height[i]; 201 initRMQ(n); 202 int ans = -1; 203 for(int i = 0;i <= len1-len2;i++) 204 { 205 int st = i; 206 int ed = len1 + 1; 207 int tmp = lcp(st,ed); 208 st += tmp; 209 ed += tmp; 210 if(ed >= n) 211 { 212 ans = i; 213 break; 214 } 215 st++; 216 ed++; 217 if(ed >= n) 218 { 219 ans = i; 220 break; 221 } 222 tmp = lcp(st,ed); 223 st += tmp; 224 ed += tmp; 225 if(ed >= n) 226 { 227 ans = i; 228 break; 229 } 230 st++; 231 ed++; 232 if(ed >= n) 233 { 234 ans = i; 235 break; 236 } 237 tmp = lcp(st,ed); 238 st += tmp; 239 ed += tmp; 240 if(ed >= n) 241 { 242 ans = i; 243 break; 244 } 245 } 246 printf("Case #%d: %d\n",iCase,ans); 247 } 248 return 0; 249 }