zoukankan      html  css  js  c++  java
  • 题解 洛谷 P4221 【[WC2018]州区划分】

    一个州不合法为其内部有欧拉回路,即图连通且每个点度数都为偶数。

    (n) 很小,考虑用状压 (DP) 解决本题,设 (f_S) 为集合 (S) 的答案,$ g_S $ 为集合 (S)(w) 和的 (p) 次方。

    得转移方程为:

    [ f_S= frac{1}{g_S} sum_{ T subset S } f_T g_{S-T} ]

    其中 (S,T,S-T) 都为合法的集合。直接枚举子集转移是 (O(n^3)),复杂度无法接受,观察式子后,发现用子集卷积优化即可,

    (code:)

    #include<bits/stdc++.h>
    #define maxn 25
    #define maxm 510
    #define maxs 2400010
    #define p 998244353
    #define lowbit(x) (x&(-x))
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    ll n,m,k,all;
    ll v[maxn],fa[maxn],d[maxn];
    ll f[maxn][maxs],g[maxn][maxs],sum[maxs],inv[maxs],cnt[maxs];
    struct edge
    {
        int x,y;
    }e[maxm];
    int find(int x)
    {
        return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    void FWT(ll *a,int type)
    {
        for(int len=1;len<all;len<<=1)
            for(int i=0;i<all;i+=len<<1)
                for(int j=i;j<i+len;++j)
                    a[j+len]=(a[j+len]+a[j]*type+p)%p;
    }
    ll qp(ll x,ll y)
    {
        ll v=1;
        while(y)
        {
            if(y&1) v=v*x%p;
            x=x*x%p,y>>=1;
        }
        return v;
    }
    bool check(int s)
    {
        if(cnt[s]<=1) return false;
        memset(d,0,sizeof(d));
        for(int i=1;i<=n;++i) fa[i]=i;
        int num=0;
        for(int i=1;i<=m;++i)
        {
            int x=e[i].x,y=e[i].y;
            if(!(s&(1<<(x-1)))||!(s&(1<<(y-1)))) continue;
            if(find(x)!=find(y)) fa[find(x)]=find(y),num++;
            d[x]++,d[y]++;
        }
        if(num!=cnt[s]-1) return true;
        for(int i=1;i<=n;++i)
            if(d[i]&1)
                return true;
        return false;
    }
    int main()
    {
        read(n),read(m),read(k),all=1<<n;
        for(int i=1;i<all;++i) cnt[i]=cnt[i-lowbit(i)]+1;
        for(int i=1;i<=m;++i) read(e[i].x),read(e[i].y);
        for(int i=1;i<=n;++i) read(v[i]);
        for(int s=0;s<all;++s)
        {
            for(int i=1;i<=n;++i)
                if(s&(1<<(i-1)))
                    sum[s]+=v[i];
            sum[s]=qp(sum[s],k),inv[s]=qp(sum[s],p-2);
            if(check(s)) g[cnt[s]][s]=sum[s];
        }
        f[0][0]=1,FWT(f[0],1);
        for(int i=0;i<=n;++i) FWT(g[i],1);
        for(int i=1;i<=n;++i)
        {
            for(int j=0;j<i;++j)
                for(int s=0;s<all;++s)
                    f[i][s]=(f[i][s]+f[j][s]*g[i-j][s]%p)%p;
            FWT(f[i],-1);
            for(int s=0;s<all;++s) f[i][s]=f[i][s]*inv[s]%p;
            FWT(f[i],1);
        }
        FWT(f[n],-1),printf("%lld",f[n][all-1]);
        return 0;
    }
    
  • 相关阅读:
    让Div居中的方法
    创建对象的几种方式
    [Gport]2014移动互联网趋势——100名CEO的一句话解读
    专访腾讯云陈磊:微信云助力企业转型把握O2O时代价值
    Head First Python 学习笔记(第二章:分享你的代码)
    Head First Python 学习笔记(第一章:使用IDLE来帮助学习Python)
    《写给大家看的设计书》学习笔记
    用TreeView以递归显示选择磁盘上文件夹中全部文件夹和文件
    WebBrowser实现:自动填充网页上的用户名和密码并点击登录按钮
    C#调用免费天气预报WebService
  • 原文地址:https://www.cnblogs.com/lhm-/p/13383482.html
Copyright © 2011-2022 走看看