zoukankan      html  css  js  c++  java
  • 6554. 【GDOI2020模拟4.11】赢家(winner)

    题目描述

    PinkRabbit 是一位人赢。
    福州市可以抽象成一个n个点m条边的,不包含重边与自环的无向图,PinkRabbit 住在1号
    点,而他的妹子住在2号点。
    某一天,PinkKitten 施放了一个大魔法,让这个无向图上所有的边都变成了单向边。现在
    PinkRabbit 关心的是他是否能够和他的妹子见面。
    具体地,PinkRabbit 能和他的妹子见面,当且仅当存在一个点 u,满足新图上从1号点出发能够
    到达u,从2号点出发也能到达 。
    现在你需要计算出,在把所有 m条边进行定向的所有2^m 种方案中,有多少种方案能让
    PinkRabbit 和他的妹子见面。你只需输出其对10^9+7 取模后的结果。

    题解

    容斥,方案=总方案-不连通

    设f[s]表示1/2能且只能到集合s的方案,转移枚举子集S容斥,S内部连通,另一半T方向随便,S-T之间的边全部指向S

    算答案类似,枚举1/2能到的S/T,内部连通,指向ST的边单向,其余的任意

    注意ST之间不能有连边

    写好一些+卡空间可以做到O(3^n),但和O(3^n*n)差不多

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define mod 1000000007
    #define ll long long
    #define file
    using namespace std;
    
    int g[16][32768],h[32768],n,m,i,j,k,l,id,L,s;
    ll p[176],f[32768],ans;
    bool a[16][16];
    
    void work(int t)
    {
    	f[p[t-1]]=1;
    	for (i=p[t-1]+4; i<=L; i+=4)
    	{
    		f[i]=p[h[i]];
    		j=i-4;
    		do {j&=i; f[i]=(f[i]-f[j]*p[h[i^j]])%mod; j-=4;} while (j>0);
    	}
    }
    
    int main()
    {
    	freopen("winner.in","r",stdin);
    	#ifdef file
    	freopen("winner.out","w",stdout);
    	#endif
    	
    	scanf("%d%d%d",&n,&m,&id);
    	fo(i,1,m) scanf("%d%d",&j,&k),a[j][k]=a[k][j]=1;
    	p[0]=1; fo(i,1,n*(n-1)/2) p[i]=p[i-1]*2%mod; L=p[n-1]*2-1;
    	
    	fo(i,1,n)
    	{
    		fo(j,1,L)
    		{
    			fo(k,1,n)
    			if (j&p[k-1])
    			{g[i][j]=g[i][j^p[k-1]]+a[i][k];break;}
    		}
    	}
    	fo(i,1,L)
    	{
    		fo(j,1,n)
    		if (i&p[j-1])
    		{h[i]=h[i^p[j-1]]+g[j][i^p[j-1]];break;}
    	}
    	work(1);work(2);
    	
    	ans=p[m];
    	for (l=3; l<=L; l+=4)
    	{
    		i=l-2;
    		do{
    			i&=l;j=l^i;
    			s=m-h[i]-h[j];
    			fo(k,1,n)
    			{
    				if (!(i&p[k-1]) && !(j&p[k-1])) s-=g[k][i]+g[k][j];
    				if (i&p[k-1] && g[k][j]) break;
    			}
    			if (k>n) ans=(ans-f[i]*f[j]%mod*p[s])%mod;
    			i-=4;
    		}while (i>0);
    	}
    	printf("%lld
    ",(ans+mod)%mod);
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    字节跳动2020年九月笔试题-爬楼梯(不能连续爬两个两步)
    c/c++经典面试题-part1
    C++单例模式之一见钟情
    多线程同步的四种方式(史上最详细+用例)
    c++多态之动态绑定
    Redis从入门到入坑
    编写一个 C 函数,该函数在一个字符串中找到可能的最长的子字符串,且该字符串 是由同一字符组成的。
    面试之进制转换函数
    c++编程题之空调遥控器
    static 和 const关键字的作用
  • 原文地址:https://www.cnblogs.com/gmh77/p/12691717.html
Copyright © 2011-2022 走看看