[題解]Mail.Ru Cup 2018 Round 1 - D. Changing Array

【題目】ios

D. Changing Arrayide

【描述】spa

給n個整數a[1],...,a[n],知足0<=a[i]<=2^k-1。Vanya能夠對這n個數中任一多個數進行操做,即將x變爲x',其中x'指x限制在k位內二進制取反。問a[1],...,a[n]中最多有多少個連續子段的異或和不爲0。3d

數據範圍:1<=n<=200000,1<=k<=30code

【思路】blog

爲了敘述方便,記MAX=(1<<k)-1,即二進制下k位全是1的數。ci

爲了符號表示不產生歧義,如下使用^表示異或(上面的題目描述中指的是次方)。get

這裏要用到異或運算的一個很重要的性質,即x^x=0。string

根據定義,x^x'=MAX,從而x'=x^x^x'=x^MAX。it

先不考慮a[1],...,a[n]的變化。維護前綴異或和s[i],因而a[i]^...^a[j]=s[j]^s[i-1]。那麼,a[i]^...^a[j]==0當且僅當s[j]==s[i-1]。爲了讓連續子段異或和爲0儘可能少,就是要讓s[i]儘可能不一樣。

再看改變某個a[i]會帶來的影響。將某個a[i]變爲a[i]^MAX,那麼包含a[i]的前綴異或和s[j]都要變爲s[j]^MAX,即s[j]變爲s[j]^MAX對全部j>=i。這個時候發現,若是再改變a[i+1],則s[k]又都變回去了對全部k>=i+1。這說明能夠經過改變某些a[i]實現將某一個s[j]變爲s[j]^MAX。

這個時候有個很天然的想法就是,值爲x和x^MAX的那些s[i]應該放在一類中考慮,由於它們最多隻有兩個值,要想使得「在其中挑兩個數,它們不相等」的機率最小,只能讓取x和x^MAX的數字個數儘可能平均,即相等或者相差1。

肯定s[i]的取值以後(有多少個s[i]取某個值x或者x^MAX),記第k個取值的s[i]共有nk個,因而最終的答案爲

注意:要注意取值範圍,要開long long!【比賽中第一次提交就由於這個問題WA了……

【個人實現】

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 
 7 using namespace std;
 8 #define MaxN 200030
 9 
10 long long s[MaxN];
11 
12 int main()
13 {
14     long long n, k;
15     long long i, j;
16     long long cnt, ans, tmp;
17     long long x;
18     long long MAX;
19     //scanf("%d%d", &n, &k);
20     cin >> n >> k;
21     MAX = (1<<(long long)k)-1;
22     s[0] = 0;
23     for(i = 1; i <= n; i++)
24     {
25         cin >> x;
26         s[i] = s[i-1] ^ x;
27     }
28     for(i = 0; i <= n; i++)
29         s[i] = min(s[i], MAX^s[i]);
30     sort(s, s+n+1);
31     cnt = 0;
32     ans = (n+1) * n / 2;
33     for(i = 0; i <= n; i++)
34     {
35         if(i == 0 || s[i] == s[i-1])
36             cnt++;
37         else
38         {
39             if(cnt % 2) //奇數
40             {
41                 tmp = cnt / 2;
42                 ans -= tmp * (tmp-1) / 2;
43                 tmp = cnt / 2 + 1;
44                 ans -= tmp * (tmp-1) / 2;
45             }
46             else
47             {
48                 tmp = cnt / 2;
49                 ans -= tmp * (tmp-1);
50             }
51             cnt = 1;
52         }
53     }
54     if(cnt % 2) //奇數
55     {
56         tmp = cnt / 2;
57         ans -= tmp * (tmp-1) / 2;
58         tmp = cnt / 2 + 1;
59         ans -= tmp * (tmp-1) / 2;
60     }
61     else
62     {
63         tmp = cnt / 2;
64         ans -= tmp * (tmp-1);
65     }
66     cout<< ans;
67     return 0;
68 }
View Code

【評測結果】

相關文章
相關標籤/搜索