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 }
    代码君
  • 相关阅读:
    解析json字符串
    python学习(十)文件操作方式
    python学习(九)集合
    python学习(八)内存地址及深/浅拷贝
    python学习(七)列表/字典合并、布尔型、交换变量值、列表转换字符串连接和分割
    python学习(六)字符串
    Python学习(五)字典
    python学习(四)数组,字符串,元组
    python学习(四)列表(数组)
    python学习(三)字符串格式化&strip的用法&小练习
  • 原文地址:https://www.cnblogs.com/kuangbin/p/3744817.html
Copyright © 2011-2022 走看看