BZOJ4347: [POI2016]Nim z utrudnieniem
BZOJ4347: [POI2016]Nim z utrudnieniem
https://lydsy.com/JudgeOnline/problem.php?id=4347
分析:
- 设\(f[i][j][k]\)表示前\(i\)堆石子选出\(nd+k\)堆使得异或和为\(j\)的方案数。
- 那么这个直接转移是\(O(n^2d)\)的。
- 注意到\(m\)特别小。
- 把石子按\(a_i\)排序之后处理即可,时间复杂度\((md)\)
- 这题卡空间,不能用滚动数组。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define N 500050
#define M 1050050
#define mod 1000000007
typedef long long ll;
int n,a[N],d;
int f[M][10],g[M],Lg[M],h[M];
void upd(int &x,int y) {
x=x+y; if(x>=mod) x-=mod;
}
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,10000,stdin),p1==p2)?EOF:*p1++)
int rd() {
int x=0; char s=nc();
while(s<'0') s=nc();
while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
return x;
}
int main() {
n=rd(), d=rd();
int i,sum=0,mx=0,j,k;
for(i=1;i<=n;i++) a[i]=rd(),sum^=a[i],mx=max(mx,a[i]);
sort(a+1,a+n+1);
for(Lg[0]=-1,i=1;i<=mx;i++) Lg[i]=Lg[i>>1]+1;
f[0][0]=1;
for(i=0;i<n;i++) {
int len=1<<(Lg[a[i]]+1),t=a[i+1];
for(j=0;j<len;j++) h[j]=f[j][d-1];
for(k=d-2;k>=0;k--) {
for(j=0;j<len;j++) g[j]=f[j][k];
for(j=0;j<len;j++) {
upd(f[j^t][k+1],g[j]);
}
}
for(j=0;j<len;j++) {
upd(f[j^t][0],h[j]);
}
}
if(n%d==0) f[sum][0]--;
printf("%d\n",(f[sum][0]+mod)%mod);
}