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的能力了。

 

来代码吧!

2014 ACM/ICPC 北京邀请赛 部分 题解
  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 的时候

 

代码:

2014 ACM/ICPC 北京邀请赛 部分 题解
 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下就是答案了,情况不多的,很少。

很黄很暴力啊^_^

2014 ACM/ICPC 北京邀请赛 部分 题解
  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个循环了,就是要体现暴力性!!

 

2014 ACM/ICPC 北京邀请赛 部分 题解
  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个不同。

然后矩阵也很好写了。

注意是要想状态转移方程。

2014 ACM/ICPC 北京邀请赛 部分 题解
 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

 

属于暴力搞过去了,没啥算法。

读懂题就可以了

2014 ACM/ICPC 北京邀请赛 部分 题解
 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

一前一后预处理下,很水。

2014 ACM/ICPC 北京邀请赛 部分 题解
 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才过

2014 ACM/ICPC 北京邀请赛 部分 题解
  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 }
代码君

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(ICPC)