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);
}

猜你喜欢

转载自www.cnblogs.com/suika/p/10229781.html
z