2014 ACM/ICPC 北京邀请赛 部分 题解

题目链接:http://acm.bnu.edu.cn/bnuoj/problem.php?search=2014+ACM-ICPC+Beijing+Invitational+Programming+Contest

总共十道题, 又结束了一场逗比的比赛, 感觉后半场都在梦游,结果被虐了!!!!大家都虐我一万里啊。

正如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 }
代码君

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2014-05-22 00:40  kuangbin  阅读(5103)  评论(0编辑  收藏  举报

导航

JAVASCRIPT: