zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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("
    ");
    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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",iCase,ans);
    247     }
    248     return 0;
    249 }
    代码君
  • 相关阅读:
    Python基础语法 第2节课(数据类型转换、运算符、字符串)
    python基础语法 第5节课 ( if 、 for )
    python基础语法 第4节课 (字典 元组 集合)
    Python基础语法 第3节课 (列表)
    A. Peter and Snow Blower 解析(思維、幾何)
    C. Dima and Salad 解析(思維、DP)
    D. Serval and Rooted Tree (樹狀DP)
    C2. Balanced Removals (Harder) (幾何、思維)
    B. Two Fairs 解析(思維、DFS、組合)
    D. Bash and a Tough Math Puzzle 解析(線段樹、數論)
  • 原文地址:https://www.cnblogs.com/kuangbin/p/3744817.html
Copyright © 2011-2022 走看看