1. 程式人生 > >bzoj 3811: 瑪裏茍斯【線性基+期望dp】

bzoj 3811: 瑪裏茍斯【線性基+期望dp】

cpp etc sin har 元素 方法 class sig 如果

這個輸出可是有點惡心啊……WA*inf,最後抄了別人的輸出方法orz
還有註意會爆long long,要開unsigned long long
對於k==1,單獨考慮每一位i,如果這一位為1則有0.5的概率貢獻1<<i,否則沒有貢獻,因為這一位選了奇數偶數個1的概率是一樣的
對於k==2,考慮乘法的意義,也就是i位和j位同時為1的概率p,貢獻(1<<(i+j))*p,這個p,如果全部的a[k]都是在i位和j為相同則是p=0.5(因為這樣一來ij的值就關聯了),否則p=0.25
對於剩下的,建線性基後最多有21個元素,直接枚舉所有狀態即可

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=100005;
unsigned long long n,m,k,a[N],b[65],tot,ans,res;
unsigned long long read()
{
    unsigned long long r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void ins(unsigned long long x)
{
    for(int i=63;i>=0;i--)
        if(x>>i)
        {
            if(!b[i])
            {
                b[i]=x;
                return;
            }
            x^=b[i];
        }
}
int main()
{
    n=read(),k=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    if(k==1)
    {
        for(int i=1;i<=n;i++)
            ans|=a[i];
        printf("%llu",ans>>1),puts((ans&1)?".5":"");
        return 0;
    }
    if(k==2)
    {
        unsigned s=0;
        for(int i=1;i<=n;i++) 
            s|=a[i];
        for(int i=0;i<32;i++)
            for(int j=0,fl=0;j<32;++j,fl=0)
                if((s>>i&1)&&(s>>j&1))
                {
                    for(int k=1;k<=n;k++)
                        if((a[k]>>i&1)^(a[k]>>j&1))
                        {
                            fl=1;
                            break;
                        }
                    if(i+j-1-fl<0) 
                        ++res;
                    else ans+=1llu<<(i+j-1-fl);
                }
        ans+=res>>1;
        printf("%llu",ans),puts((res&1)?".5":"");
        return 0;
    }
    unsigned long long ans=0;
    for(int i=1;i<=n;i++)
        ins(a[i]);
    // for(int i=0;i<=20;i++)
        // cerr<<b[i]<<" ";cerr<<endl;
    for(m=22;!b[m];m--);
    m++;
    for(int s=0,len=(1<<m);s<len;s++)
    {
        unsigned long long sm=0,r=1;
        for(int i=0;i<m;i++)
            if(s&(1<<i))
                sm^=b[i];
        for(int i=1;i<k;i++) 
            r*=sm;
        if(r<len)
        {
            r*=sm,tot+=r;
            if(tot>=len) 
                ans+=tot/len,tot%=len;
        }
        else
        {
            ans+=r/len*sm,r%=len,r*=sm,tot+=r;
            if(tot>=len) 
                ans+=tot/len,tot%=len;
        }
    }
    printf("%llu",ans),puts(tot?".5":"");
    return 0;
}

bzoj 3811: 瑪裏茍斯【線性基+期望dp】