AtCoder Grand Contest 043B(组合数学)

先进行一次绝对值差分,把序列中的数都变成 0,1,2 。如果序列中存在 1,答案只能是 0 或 1;如果不存在 1,答案只能是 0 或 2。对于不存在 1 的情况,我们可以将每个数都 除以2,最后再将答案 乘2,这显然是等价的。于是现在答案只能是 0 或 1 ,发现绝对值差分等价于异或。现在问题转化为一个 只包含0和1的序列,每次将相邻两个数异或,求最后剩下的数。那么考虑每个数会被异或几次即可,设序列长度为 n,则位置 i 上的数会被异或 (n−1,i−1) 次。这时候我们还要求出模 2 意义下的组合数,一个简单的方法是计算每个阶乘的分解中 2 的次数,将计算组合数时的除法改为做减法。则对于一个组合数,最后如果剩下的 2 的次数为 0,则说明 mod2=1,否则 mod2=0。对于阶乘的分解,可以先对每个数简单地求出分解中 2 的次数,然后做前缀和即可。时间复杂度 O(n)。

 1 #define HAVE_STRUCT_TIMESPEC
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 int a[1000007],c[1000007];
 5 char s[1000007];
 6 int main() {
 7     ios::sync_with_stdio(false);
 8     cin.tie(NULL);
 9     cout.tie(NULL);
10     int n;
11     cin>>n;
12     cin>>s+1;
13     --n;
14     for(int i=1;i<=n;++i)
15         a[i]=abs(s[i]-s[i+1]);
16     int flag=0;
17     for(int i=1;i<=n;++i)
18         if(a[i]==1)
19             flag=1;
20     if(!flag)
21         for(int i=1;i<=n;++i)
22             a[i]>>=1;
23     for(int i=1;i<=n;++i){
24         int x=i;
25         while(!(x&1))
26             ++c[i],x>>=1;
27         c[i]+=c[i-1];
28     }
29     int ans=0;
30     for(int i=1;i<=n;++i)
31         ans^=c[n-1]-c[i-1]-c[n-i]?0:(a[i]&1);
32     if(!flag)
33         ans<<=1;
34     cout<<ans;
35     return 0;
36 }
原文地址:https://www.cnblogs.com/ldudxy/p/12601250.html