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
",(f[sum][0]+mod)%mod);
}
原文地址:https://www.cnblogs.com/suika/p/10229781.html