zoukankan      html  css  js  c++  java
  • 「WC 2018」州区划分

    博主的 (mathtt{BiBi}) 时间

    感觉学到了几个卡常小技巧。(这题卡空间又卡时间可还行)

    话说在 (mathtt{usOJ}) 上只有 (50pts)。(其他都可过)

    ( ext{Solution})

    可以发现,不合法的州就是内部有欧拉回路的州。

    因此,我们只需要判断州联通且没有奇数度的点,这个州就不合法。

    我们令 (f[S]) 为总集合为 (S) 时的答案,(g[S])(S) 集合的 (w) 值之和的 (p) 次方。

    这里有一个在本蒟蒻眼中看起来并不显然的 (mathtt{DP})

    [f[S]=frac{1}{g[S]}*sum_{S'subset S}f[S']*g[S-S'] ]

    其实就是把 (S-S') 看作新划分的一个州,把前面的分式提进去就是新划分的州的贡献((frac{g[S-S']}{g[S]}))。那么 (f[S]) 其实是多个划分的乘积之和。

    然后可以把式子转化为:

    [f[S]=sum f[S_0]g[S_1] ]

    其中 (S_0igcup S_1=S,S_0igcap S_1=emptyset)

    这就是子集卷积。所以关于条件二,我们套路地加上一维表示这个集合中 (1) 的个数。

    [f[i][S]=sum f[j][S0]*g[i-j][S1] ]

    然后就可以用 (mathtt{FWT}) 了。

    ( ext{Code})

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    const int mod=998244353;
    
    int n,m,p,u[400],v[400],w[25],lim,fa[25],deg[25],cnt,val[(1<<21)+5],f[25][(1<<21)+5],g[25][(1<<21)+5],bit[(1<<21)+5],inv[(1<<21)+5];
    bool ok[(1<<21)+5];
    
    inline void inc(int &x,const int y) {
        x=x+y;
        if(x>=mod) x=x-mod;
        if(x<0) x=x+mod;
    }
    
    inline int mul(const int x,const int y) {return 1ll*x*y-1ll*x*y/mod*mod;}
    
    int Find(int x) {return x==fa[x]?x:fa[x]=Find(fa[x]);}
    
    int qkpow(int x,int y) {
        int r=1;
        while(y) {
            if(y&1) r=mul(r,x);
            x=mul(x,x); y>>=1;
        }
        return r;
    }
    
    void FWT_or(int *t,const int op=1) {
        for(int i=2;i<=lim;i<<=1)
            for(int p=(i>>1),j=0;j<lim;j=j+i)
                for(int k=j;k<j+p;++k)
                    inc(t[k+p],t[k]*op);
    }
    
    int main() {
        int x,y;
        n=read(9),m=read(9),p=read(9); lim=1<<n;
        rep(i,1,m) u[i]=read(9),v[i]=read(9);
        rep(i,1,n) w[i]=read(9);
        rep(S,0,lim-1) {
            cnt=0;
            rep(i,0,n-1) {
                if((S>>i)&1) ++cnt,val[S]+=w[i+1];
                deg[i+1]=0,fa[i+1]=i+1;
            }
            bit[S]=cnt;
            rep(i,1,m)
                if(((S>>u[i]-1)&1)&&((S>>v[i]-1)&1)) {
                    x=Find(u[i]),y=Find(v[i]);
                    if(x^y) fa[x]=y,--cnt;
                    ++deg[u[i]],++deg[v[i]];
                }
            if(cnt>1) ok[S]=1;
            cnt=0;
            rep(i,1,n) cnt+=(deg[i]&1);
            if(cnt) ok[S]=1;
            if(ok[S])
                g[bit[S]][S]=qkpow(val[S],p);
            inv[S]=qkpow(qkpow(val[S],mod-2),p);
            // 注意不是在 S 是合法州时才算 inv,因为 f[S] 可以表示几个州合在一起的方案
        }
        f[0][0]=1;
        FWT_or(f[0]);
        rep(i,0,n) FWT_or(g[i]);
        rep(i,1,n) {
            rep(j,0,i-1)
                rep(k,0,lim-1)
                    inc(f[i][k],mul(f[j][k],g[i-j][k]));
            FWT_or(f[i],-1);
            rep(j,0,lim-1) // 因为 f[i] 会在之后做出贡献,需要将不合法的清空,记得除以 g[j]
                if(bit[j]^i) f[i][j]=0;
                else f[i][j]=mul(f[i][j],inv[j]);
            if(i^n) FWT_or(f[i]);
        }
        print(f[n][lim-1],'
    ');
        return 0;
    }
    
  • 相关阅读:
    Tensor总结
    Tensorflow池化
    conda操作
    KS值计算
    supervisor实践
    npm/yarn实践
    nni 环境搭建
    阿里云个人邮箱配置
    Jinja2宏使用
    利用VS code 远程调试 docker 中的 dotnet 应用
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/13110704.html
Copyright © 2011-2022 走看看