Woj 1553 G - Alchemy I

来源:互联网 发布:网络拓扑图生成 编辑:程序博客网 时间:2024/06/03 18:35

题目链接

n个点,m种符咒,给每个点加一个符咒,另外有p个矛盾的条件,表示某两个点不能用相同的符咒,问合法的方案数。


容斥原理,因为p的范围只有15,所以可以枚举矛盾条件,考虑0个就是+,1个就是-,2个就是+,3个就是-..........

对于某个状态子集,我们把矛盾条件进行并差集,同一个集合内的符咒相同。

假如某种状态并差集后有cnt集合,这cnt个集合共有S个元素,那么这种状态答案的绝对值就是  m ^ (cnt) * m ^ (n-S) = m^(n-s+cnt)


#include <stdio.h>#include <math.h>#include <map>#include <set>#include <string.h>#include <algorithm>using namespace std;inline int input(){    int ret=0;bool isN=0;char c=getchar();    while(c<'0' || c>'9') {        if(c=='-') isN=1;        c=getchar();    }    while(c>='0' && c<='9'){        ret=ret*10+c-'0';c=getchar();    }    return isN?-ret:ret;}#define N 100005#define mod 1000000007#define clr(a) memset(a,0,sizeof(a))typedef long long ll;int n,m,p,all,x[16],y[16];int fa[60];int one,a[20];int num[60];bool vis[60];ll ans;int tag;inline void init(){    for(int i=1;i<=n;i++) fa[i]=i;}inline int find(int x){    if(x!=fa[x]) return fa[x]=find(fa[x]);    return x;}inline ll Pow(ll a,ll b){    ll d=1,t=a;    while(b){        if(b&1) d=d*t%mod;        b>>=1,t=t*t%mod;    }    return d;}int main(){    while(~scanf("%d",&n)){        tag=1;m=input();p=input();        for(int i=0;i<p;i++){            x[i]=input(),y[i]=input();            if(x[i] == y[i]) tag=0;        }        if(!tag) puts("0");        else{            all = 1<<p;            ans=0;            for(int i=0;i<all;i++){                init();                clr(vis);                clr(num);                one=0;                for(int j=0;j<p;j++){                    if(i&(1<<j)){                        a[one++]=j;                        vis[x[j]]=vis[y[j]]=1;                    }                }                one%2?tag=-1:tag=1;                for(int j=0;j<one;j++){                    int X=find(x[a[j]]);                    int Y=find(y[a[j]]);                    if(X!=Y) fa[X]=Y;                }                for(int i=1;i<=n;i++){                    if(vis[i]) num[find(i)]++;                }                int cnt=0,S=0;                for(int i=1;i<=n;i++){                    if(num[i]!=0){                        cnt++;                        S+=num[i];                    }                }                ans+=tag*Pow(m,n+cnt-S);            }            while(ans<0) ans+=mod;            printf("%lld\n",ans%mod);        }    }    return 0;}


0 0
原创粉丝点击