hdu5715 XOR 游戏 [2016百度之星复赛D题]

   比赛的时候没仔细想,赛后一想这题其实挺简单的,先求出序列的异或前缀和,然后将异或前缀和建出一颗trie树,然后我们可以二分答案,把问题变成判定性问题,判定是否存在一种方案,使得所有的分组的异或和都大于等于这个二分的答案,然后就可以dp了,用f[i][j]表示到j为止能不能分成i组,f[i][j]=f[i-1][j-k]|f[i-1][j-k+1]...|f[i-1][j-1],这个东西用trie树维护一下就可以了。单组数据复杂度O(nmlogn^2)

  代码

 1 #include<cstdio>
 2 const int N = 1001010;
 3 int num[N],Num[N],trie[N][2],tt,sum[N];
 4 int n,m,l,r,i,k,j,a[N],mid;
 5 int flag[11][N];
 6 void add(int x,int y)
 7 {
 8     int i;
 9     for (i=0;i<=31;i++)
10     num[i]=x&1,x>>=1;
11     int t=0;
12     for (i=31;i>=0;i--)
13     {
14         if (trie[t][num[i]]==0) trie[t][num[i]]=++tt;
15         t=trie[t][num[i]];
16         sum[t]+=y;
17     }
18 }
19 int find(int x,int y)
20 {
21     int i;
22     for (i=0;i<=31;i++)
23     {
24         num[i]=x&1,x>>=1;
25         Num[i]=y&1,y>>=1;    
26     }
27     int t=0;
28     for (i=31;i>=0;i--)
29     {
30         if (Num[i]==1)
31         {
32             if (!sum[trie[t][1-num[i]]]) return 0;
33             else t=trie[t][1-num[i]];
34         }
35         else
36         {
37             if (sum[trie[t][1-num[i]]]) return 1;
38             else if (!sum[trie[t][num[i]]]) return 0;
39             else t=trie[t][num[i]];
40         }
41     }
42     return 1;
43 }
44 int check(int x)
45 {
46     int i,j;
47     for (i=0;i<=m;i++)
48     for (j=0;j<=n;j++)
49     flag[i][j]=0;
50     flag[0][0]=1;
51     for (i=1;i<=m;i++)
52     {
53         for (j=0;j<=tt;j++) sum[j]=0;
54         for (j=0;j<=n;j++)
55         {
56             if (j-k-1>=0)
57             if (flag[i-1][j-k-1]) add(a[j-k-1],-1);
58             flag[i][j]=find(a[j],x);
59             if (flag[i-1][j]) add(a[j],1);
60         }
61     }
62     return flag[m][n];
63 }
64 int main()
65 {
66     int test;
67     scanf("%d",&test);
68     for (int ii=1;ii<=test;ii++)
69     { 
70     for (i=0;i<=tt;i++)
71     trie[i][0]=trie[i][1]=0;
72     tt=0;
73     scanf("%d%d%d",&n,&m,&k);
74     for (i=1;i<=n;i++)
75     {
76         scanf("%d",&a[i]);
77         a[i]^=a[i-1];
78     }
79     for (i=0;i<=n;i++)
80     add(a[i],0);
81     l=1;r=2000000000;
82     while (l<=r)
83     {
84         mid=(l+r)>>1;
85         if (check(mid)) l=mid+1;else r=mid-1;
86     }
87     printf("Case #%d:
",ii); 
88     printf("%d
",r);
89     } 
90 }
原文地址:https://www.cnblogs.com/fzmh/p/5540245.html