你取个模会死,吗,,,
Silviasylvia · · 题解
首先有一种暴力方法,就是位数从高到低直接数位 dp,记录当前每一个数的上限是否取满了,但这样复杂度显然是爆炸的。我们考虑有没有什么性质可以优化这个过程。
异或有一个很优秀的性质;
然后就容易多了,首先不难发现如果
于是顺着这个思路从高位考虑,当前在第
假如有
具体的,设
一些细节:
- 如果当前位为
1 的个数是偶数(第0 位除外),那么最终的dp 值就需要减去\prod\limits_{i=1}^n((a_i\mod 2^j)+1) ,因为这包含了全部选的方案,但是如果全部选的话实际上应该考虑在j-1 的子问题中,所以不能算。 - 你在算有
1 的最高位的贡献的时候,会把全部是0 的方案算进去,因此最终 ans 要减1 。 - 如果当前位有奇数个
1 ,那么统计完就直接退出循环(显然)。 - 答案会爆 ll,建议开 int128。
复杂度
核心代码:
rdn;
upn rd(a[i]);
int ans=0;
pu(j,31,0)
{
int st=0;
up(i,1,n)
{
if(a[i]&(1<<j))++st;
}
dp[0][0]=1;
int ww=1;
up(i,1,n)
{
if(a[i]&(1<<j))
{
dp[i][0]=dp[i-1][1]*(a[i]%(1<<j)+1);
dp[i][1]=dp[i-1][0]*(a[i]%(1<<j)+1);
dp[i][0]+=dp[i-1][0]*(1<<j);
dp[i][1]+=dp[i-1][1]*(1<<j);
}
else
{
dp[i][0]=dp[i-1][0]*(a[i]%(1<<j)+1);
dp[i][1]=dp[i-1][1]*(a[i]%(1<<j)+1);
}
ww*=(a[i]%(1<<j)+1);
}
int vl=0;
vl=dp[n][0];
if(st%2==0)vl-=ww;
if(st%2==0&&j==0)vl+=ww;
vl/=(1<<j);
ns+=vl;
if(st&1)
{
break;
}
}
print(ans-1);