• 五校联考R1 Day2T2 矩阵matrix(容斥)


    题目链接

    容易想到容斥,但是很恶心,因为要对行和列都容斥,然后行+列又要容斥。。
    于是得到(O(nmlog))的做法。
    就有70分了:

    #include <cstdio>
    #include <algorithm>
    #define mod (1000000007)
    #define Mod(x) (x>mod&&(x-=mod))//>=
    #define ID(x,y) ((x-1)*m+y)
    typedef long long LL;
    const int N=1e5+5,M=1005;
    
    int n,m;
    
    namespace Subtask1
    {
    	int Cn[N],Cm[N],inv[N];
    	inline LL FP(LL x,LL k)
    	{
    		LL t=1;
    		for(; k; k>>=1,x=x*x%mod)
    			if(k&1) t=t*x%mod;
    		return t;
    	}
    	LL Calc(LL n,LL m,int *C)
    	{
    		LL res=0;
    		for(int i=1; i<=n; ++i)
    			if(i&1) res+=1ll*C[i]*FP(2,(n-i)*m)%mod;
    			else res-=1ll*C[i]*FP(2,(n-i)*m)%mod;
    		return (res%mod+mod)%mod;
    	}
    	LL Unique(LL n,LL m)
    	{
    		LL res=0;
    		for(int i=1; i<=n; ++i)
    			for(int j=1; j<=m; ++j)
    				if((i+j)&1) res+=1ll*Cn[i]*Cm[j]%mod*FP(2,(n-i)*(m-j))%mod;
    				else res-=1ll*Cn[i]*Cm[j]%mod*FP(2,(n-i)*(m-j))%mod;
    		return (res%mod+mod)%mod;
    	}
    	void Main(int n,int m)
    	{
    		Cn[0]=Cm[0]=inv[1]=1;
    		for(int i=2,l=std::max(n,m); i<=l; ++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    		for(int i=1; i<=n; ++i) Cn[i]=1ll*Cn[i-1]*(n-i+1)%mod*inv[i]%mod;
    		for(int i=1; i<=m; ++i) Cm[i]=1ll*Cm[i-1]*(m-i+1)%mod*inv[i]%mod;
    //		printf("%I64d-%I64d-%I64d-%I64d
    ",FP(2,1ll*n*m),Calc(n,m,Cn),Calc(m,n,Cm),Unique(n,m)-mod);
    		printf("%I64d
    ",((FP(2,1ll*n*m)-(Calc(n,m,Cn)+Calc(m,n,Cm)+Unique(n,m))%mod)%mod+mod)%mod);
    	}
    }
    namespace TEST
    {
    	int Ans;
    	bool col[1005][1005],vis[20000001];
    	bool Checkr()//存在某行未染色的方案数 
    	{
    		for(int i=1; i<=n; ++i)
    		{
    			for(int j=m; ~j; --j)
    				if(!j) return 1;
    				else if(col[i][j]) break;
    		}
    		return 0;
    	}
    	bool Checkc()//存在某列未染色的方案数 
    	{
    		for(int j=1; j<=m; ++j)
    		{
    			for(int i=n; ~i; --i)
    				if(!i) return 1;
    				else if(col[i][j]) break;
    		}
    		return 0;
    	}
    	void DFS(int x,int y,int s)
    	{
    		if(y>m) y=1, ++x;
    		if(x>n)
    		{
    			if(!vis[s]&&Checkc())
    			{
    				puts("
    OK:");
    				for(int i=1; i<=n; ++i,putchar('
    '))
    					for(int j=1; j<=m; ++j) printf("%d ",col[i][j]);
    				++Ans, vis[s]=1;
    			}
    			return;
    		}
    		DFS(x,y+1,s), col[x][y]=1, DFS(x,y+1,s|(1<<ID(x,y)-1)), col[x][y]=0;
    	}
    	void Main()
    	{
    		DFS(1,1,0), printf("%d
    ",Ans);
    	}
    }
    
    int main()
    {
    	freopen("matrix.in","r",stdin);
    	freopen("matrix.out","w",stdout);
    
    	scanf("%d%d",&n,&m);
    	if(m==1) return putchar('1'),0;
    //	if(n==100000&&m==100000) return printf(""),0;//可能要跑2h。。没早打表
    //	TEST::Main();
    	if(n<=1000&&m<=1000||1ll*n*m<=1400000||1) {Subtask1::Main(n,m); return 0;}
    
    	return 0;
    }
    

    其实只要保证列合法,只对行容斥就可以了。
    当确定(k)行不染色时,每列合法的方案数是(2^{n-k}-1),然后(m)列的方案数就是它的(m)次方。

    #include <cstdio>
    #include <algorithm>
    #define mod (1000000007)
    typedef long long LL;
    const int N=1e5+5;
    
    int inv[N],C[N];
    
    inline LL FP(LL x,LL k)
    {
    	x<0&&(x+=mod);
    	LL t=1;
    	for(; k; k>>=1,x=x*x%mod)
    		if(k&1) t=t*x%mod;
    	return t;
    }
    LL Calc(LL n,LL m)
    {
    	LL res=0;
    	for(int i=0; i<=n; ++i)
    		if(i&1) res-=1ll*C[i]*FP(FP(2,n-i)-1,m)%mod;
    		else res+=1ll*C[i]*FP(FP(2,n-i)-1,m)%mod;
    	return (res%mod+mod)%mod;
    }
    
    int main()
    {
    	freopen("matrix.in","r",stdin);
    	freopen("matrix.out","w",stdout);
    
    	int n,m; scanf("%d%d",&n,&m);
    	C[0]=inv[1]=1;
    	for(int i=2; i<=n; ++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    	for(int i=1; i<=n; ++i) C[i]=1ll*C[i-1]*(n-i+1)%mod*inv[i]%mod;
    	printf("%I64d
    ",Calc(n,m));
    
    	return 0;
    }
    
  • 相关阅读:
    一些点子的梳理
    网络安全解决方案
    流量劫持技术
    运营商DNS系统安全解决方案
    安卓工作室 设置每次启动 选择项目,不直接打开项目
    多臂机测试, AB测试
    vue 入门
    web开发 入门
    C# .NET 使用第三方类库DotNetZip解压/压缩Zip文件
    Linq 101 工具和源码
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9540065.html
Copyright © 2020-2023  润新知