CodeForces 832E. Vasya and Shifts 高斯消元

传送门

题意

(n) 组,每组 (4) 个、长度都为 (m) 且一样的字符串,
定义了字符串的相加为模 (5) 加法。
(q) 次询问,要求回答要构成每次询问要求的字符串有多少种方案。

思路

高斯消元,答案为 (5) 的自由元个数次方。
注意将所有询问都加入常数矩阵,可以在 (O(nm(n+q))) 的时间复杂度内完成,不然会超时。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod=1e9+7;
int n,m,q;
LL a[510][810],ans,inv[5];
char s[510];

LL qpow(LL x,LL k){
	LL res=1;
	while(k){
		if(k&1) res=res*x%mod;
		x=x*x%mod;
		k>>=1;
	}
	return res;
}

int main(){
	for(int i=1;i<5;i++) inv[i]=i*i*i%5;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++) a[j][i]=s[j]-'a';
	}
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++) a[j][i+n]=s[j]-'a';
	}
	for(int i=1,pos=1;pos<=n;i++){
		//找当前主元,pos为假定的主元位 
		while(pos<=n){
			for(int j=i+1;j<=m;j++) if(a[j][pos]>0) swap(a[j],a[i]);
			//此时pos位上有不为0的系数,可以消元 
			if(a[i][pos]) break;
			
			//否则找下一位有没有不为0的系数。 
			pos++;
		}
		
		//如果pos>n,则消元结束,且自由元数量 n-i+1
		//如果方程组有解,那么答案就是 5^(n-i+1) 
		if(pos>n) {ans=qpow(5,n-i+1);break;}
		
		//消元,不要求解出方程,就没有反代了
		for(int j=i+1;j<=m;j++)
			if(a[j][pos]!=0){
				LL t=a[j][pos]*inv[a[i][pos]]%5;
				for(int k=pos;k<=n+q;k++) a[j][k]=((a[j][k]-t*a[i][k])%5+5)%5;
			}
	}
	
	//判断方程组是否有解 
	for(int i=n+1;i<=n+q;i++){
		LL temp=ans;
		for(int j=1,cnt=0;j<=m;j++,cnt=0){
			for(int k=1;k<=n;k++) cnt+=a[j][k]>0;
			//如果系数全 0,而常数非 0,则无解 
			if(!cnt&&a[j][i]) temp=0;
		}
		cout<<temp<<endl;	
	}
	return 0;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/12164521.html