- 70pts
- 就是求在一段序列中取出若干个数(不能全取完且取出的个数必须是d的倍数),使剩下的xor和为0的方案数
- f[i][k][w]表示现在到了第i个数,取出的数的个数%d==k,没取出来的数xor和为0时方案数
- 答案就是f[n][0][0]-(n%d==0) (不能全取完)
- 对于另外20%的数据,发现所有数的本质不同的xor和最多有2^5个,预处理出来本质不同的xor和,在第三维枚举转移
- 注意要使用滚动数组,每次要循环清零
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int mod=1e9+7;
int f[2][10][1<<20],a[2000000],b[10],c[1000],n,d,cnt=0,tot=0;
void upd(int &a,int b){a+=b; a-= a>=mod? mod:0;}
map<int,int> v;
void subtask1(){
f[0][0][0]=1;
rep(i,1,n){
rep(k,0,d-1){
rep(w,0,(1<<14)-1){
f[i%2][k][w]=(f[i%2][k][w]+f[(i-1)%2][(k-1+d)%d][w])%mod;
f[i%2][k][w^a[i]]=(f[i%2][k][w^a[i]]+f[(i-1)%2][k][w])%mod;
}
}
rep(k,0,d-1)rep(w,0,(1<<14)-1)f[(i-1)%2][k][w]=f[(i-1)%2][(k-1+d)%d][w]=0;
}
cout<<f[n%2][0][0]-(n%d==0);
}
void work(int S){
int now=1,tot=0;
while(S){
if(S&1)tot^=b[now];
now++;S>>=1;
}
if(v[tot]==0) c[++cnt]=tot,v[tot]=1;
}
void subtask2(){
rep(i,0,(1<<tot)-1)work(i);
sort(c+1,c+cnt+1);
f[0][0][0]=1;
rep(i,1,n){
rep(k,0,d-1){
rep(j,1,cnt){
int w=c[j];
f[i%2][k][w]=(f[i%2][k][w]+f[(i-1)%2][(k-1+d)%d][w])%mod;
f[i%2][k][w^a[i]]=(f[i%2][k][w^a[i]]+f[(i-1)%2][k][w])%mod;
}
}
rep(k,0,d-1){
rep(j,1,cnt){
int w=c[j];
f[(i-1)%2][k][w]=f[(i-1)%2][(k-1+d)%d][w]=0;
}
}
}
cout<<f[n%2][0][0]-(n%d==0);
}
int main()
{
scanf("%d%d",&n,&d);
rep(i,1,n){
scanf("%d",&a[i]);
if(v[a[i]]||tot>5)continue;
b[++tot]=a[i],v[a[i]]=1;
}
v.clear();
if(tot>5)subtask1();
else subtask2();
return 0;
}
- 100pts
- 考虑到序列的顺序和最后答案无关,把a从小到大排序,每次找到第一个(2^x)>=a[i],枚举0~2^(x+1)
- 因为\sum a[i]<=10^7所以复杂度是对的
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int mod=1e9+7;
int f[2][10][1<<21],a[2000000],n,d;
void upd(int &a,int b){a+=b; a-= a>=mod? mod:0;}
int main()
{
//freopen("a.in","r",stdin);
scanf("%d%d",&n,&d);
rep(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+n+1);
f[0][0][0]=1;
rep(i,1,n){
int now=1;
while(now<=a[i])now<<=1;
rep(k,0,d-1){
rep(w,0,now){
upd(f[i%2][k][w],f[(i-1)%2][(k-1+d)%d][w]);
upd(f[i%2][k][w^a[i]],f[(i-1)%2][k][w]);
}
}
rep(k,0,d-1)rep(w,0,now)f[(i-1)%2][k][w]=f[(i-1)%2][(k-1+d)%d][w]=0;
}
cout<<f[n%2][0][0]-(n%d==0);
return 0;
}