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;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12164521.html
今日推荐