FWT+线性基 -- 牛客网暑期ACM多校训练营(第八场)H——Playing games FWT优化dp

牛客多校
前置技能:
FWT介绍
线性基
线性基讲解

题解1
强烈推荐 题解2

#include <bits/stdc++.h>
using namespace std;
int read(){
    int x=0;
    char ch=getchar();
    while (!isdigit(ch))
        ch=getchar();
    while (isdigit(ch))
        x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    return x;
}
const int N=1<<19,mod=1e9+7,inv2=5e8+4;
int n,a[N],b[N],v=0;
void debug(int  a[],int n)
{
    cout<<"数组a为"<<endl;
   int top = 1;
   for(int i=0;i<=n;i++)
   {
       if(top)top =0;
       else printf(" ");
       printf("%d",a[i]);
   }
   printf("\n");
}
int Pow(int x,int y){
    int ans=1;
    for (;y;y>>=1,x=1LL*x*x%mod)
        if (y&1)
            ans=1LL*ans*x%mod;
    return ans;
}
void FWT(int a[],int n,int flag){
    for (int d=1;d<n;d<<=1)
        for (int i=0;i<n;i+=(d<<1))
            for (int j=0;j<d;j++){
                int x=a[i+j],y=a[i+j+d];
                a[i+j]=(x+y)%mod;
                a[i+j+d]=(x-y+mod)%mod;
                if (flag==-1){
                    a[i+j]=1LL*a[i+j]*inv2%mod;
                    a[i+j+d]=(1LL*a[i+j+d]*inv2%mod+mod)%mod;
                }
            }
}

bool check(int x,int n){
    for (int i=0;i<n;i++)
        b[i]=Pow(a[i],x);
    FWT(b,n,-1);
    b[v]=(b[v]+mod)%mod;
    return b[v]>0;
}
int main(){
    n=read();
    memset(a,0,sizeof a);
    for (int i=1;i<=n;i++){
        int x=read();
        v^=x;
        a[x]++;
    }
    a[0]++;
    int m=1<<19;
    FWT(a,m,1);
    int L=0,R=19,mid,ans=19;
    while (L<=R){
        mid=(L+R)>>1;
        if (check(mid,m))
            R=mid-1,ans=mid;
        else
            L=mid+1;
    }
    printf("%d\n",n-ans);
    return 0;
}

推荐:
FFT
FWT模板:
参考

void FWT(int a[],int n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;  
                //xor:a[i+j]=x+y,a[i+j+d]=(x-y+mod)%mod;  
                //and:a[i+j]=x+y;  
                //or:a[i+j+d]=x+y;  
            }  
}  

void UFWT(int a[],int n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod; 
                //rev表示2在模mod下的逆元 
                //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;  
                //and:a[i+j]=x-y;  
                //or:a[i+j+d]=y-x;  
            }  
}  
void solve(int a[],int b[],int n)  
{  
    FWT(a,n);  
    FWT(b,n);  
    for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%mod;  
    UFWT(a,n);  
}  

猜你喜欢

转载自blog.csdn.net/axuhongbo/article/details/81778496