正题
题目大意
定义函数f(x)(xf(x)(xf(x)(x为一个序列)))
若任意一个xi=1x_i=1xi=1那么有f(x)=1f(x)=1f(x)=1
若有一个xi=0x_i=0xi=0那么有f(x)=0f(x)=0f(x)=0
其他的,有f(x)=(∑j=1nf(x1...,xj−1,...xn))%2f(x)=(\sum_{j=1}^nf(x_{1}...,x_j-1,...x_n))\% 2f(x)=(j=1∑nf(x1...,xj−1,...xn))%2
给出li,ril_i,r_ili,ri,求∑li≤xi≤rif(x)\sum_{l_i\leq x_i\leq r_i} f(x)li≤xi≤ri∑f(x)
解题思路
我们发现对于xxx有f(x)=∏i=1n−1C∑xjxif(x)=\prod_{i=1}^{n-1}C_{\sum x_j}^{x_i}f(x)=∏i=1n−1C∑xjxi
然后又有CnkC_{n}^kCnk为奇数仅当(n+k)&k=k(n+k)\&k=k(n+k)&k=k
然后转换为f(x)=1f(x)=1f(x)=1的充要条件就是对于任意的1≤i≠j≤n1\leq i\neq j\leq n1≤i̸=j≤n有(xi+xj)&xi=xi(x_i+x_j)\& x_i=x_i(xi+xj)&xi=xi,证明
然后我们数位dpdpdp,用fi,jf_{i,j}fi,j表示到第iii位时状态jjj中0表示没有到达上界,111表示到达了上界。
对于lil_ili,我们可以对nnn维进行容斥即可。
时间复杂度O(50∗n∗(2n)2)O(50*n*(2^n)^2)O(50∗n∗(2n)2)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=10,XJQ=990804011;
ll T,n,l[N],r[N],x[N],f[60][1<<N],ans,MS;
ll solve(ll S)
{for(ll i=0;i<n;i++){x[i]=((S>>i)&1)?(l[i]-1):r[i];if(x[i]<0) return 0;}memset(f,0,sizeof(f));f[51][0]=1;for(ll i=50;i>=0;i--){for(ll j=0;j<MS;j++){if(!f[i+1][j]) continue;ll now=0;for(ll k=0;k<n;k++)now|=(1<<k)*(x[k]>>i&1);(f[i][j|now]+=(__builtin_popcount(j)+1)*f[i+1][j]+XJQ)%=XJQ;for(ll k=0;k<n;k++)if((now&(~j))>>k&1)(f[i][j|(now^(1<<k))]+=f[i+1][j]+XJQ)%=XJQ;}}ll ans=0;for(ll i=0;i<MS;i++)(ans+=f[0][i]+XJQ)%=XJQ;return ans;
}
int main()
{freopen("c.in","r",stdin);freopen("c.out","w",stdout);scanf("%lld",&T);while(T--){scanf("%lld",&n);MS=1<<n;ans=0;for(ll i=0;i<n;i++)scanf("%lld%lld",&l[i],&r[i]),l[i]--,r[i]--;for(ll i=0;i<MS;i++)(ans+=(__builtin_popcount(i)&1?XJQ-solve(i):solve(i))+XJQ)%=XJQ;printf("%lld\n",ans);}
}