ICPC2019 沈阳网络赛 K.Guanguan's Happy water(高斯消元+逆元+矩阵快速幂)

题目链接

https://nanti.jisuanke.com/t/41411

思路

怎么说呢,这题就是让你先解模线性方程组,然后用矩阵快速幂算数列前n项和。虽说跟模板题很接近但也有160多行代码,我觉得写起来还是很繁琐的,调试起来也不简单。这里不多说了,就把这题当作高斯消元模板记录一下吧。

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=80;
const ll mod=1e9+7;
typedef ll Mat[maxn][maxn];
ll p[maxn],f[maxn*2],sum[maxn*2],n,k;
Mat A;
void read(ll &x)
{
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

//高斯消元部分 
//填数 
void solve(){
    memset(A,0,sizeof(A));
    ll cur=k+1;
    //cout<<"f"<<endl;
	for(ll i=0;i<k;i++){
        for(ll j=0;j<k;j++){
            A[i][j]=f[cur-1-j];
        }
        A[i][k]=f[cur];
        cur++;
    }
}

ll pow_mod(ll x, ll k, ll mod) {
    ll ret=1;
    while(k){
        if(k&1)
            ret=ret*x%mod;
        x=x*x%mod;
        k>>=1;
    }
    return ret;
}
ll inv(ll v,ll modd){
    return pow_mod(v%modd,modd-2,modd);
}

void gauss_elimin(){
    for(ll i=0;i<k;i++){
        ll r=i;
        for(ll j=i+1;j<k;j++)
            if (A[r][i]<A[j][i])
                r=j;
        if(r!=i){
            for(ll j=0;j<=k;j++)
                swap(A[i][j],A[r][j]);
        }
        if(A[i][i]==0)
            continue;
            
        for(ll l=i+1;l<k;l++){
            ll f=A[l][i]*inv(A[i][i],mod)%mod;
            for(ll j=i;j<=k;j++)
            	A[l][j]=((A[l][j]-A[i][j]*f)%mod+mod)%mod;
        }
    }
    for(ll i=k-1;i>=0;i--){
        for(ll j=i+1;j<k;j++)
            A[i][k]=((A[i][k]-A[i][j]*A[j][k])%mod+mod)%mod;
        A[i][k]=A[i][k]*inv(A[i][i],mod)%mod;
    }
    for(ll i=0;i<k;i++)p[i]=A[i][k];
    //for(ll i=0;i<k;i++)cout<<p[i]<<" ";cout<<endl;
}

//矩阵快速幂部分 
int len; 
struct matt{
    ll mt[101][101];
    matt(){
    	memset(mt,0,sizeof(mt));
    }
};
matt a,e;
matt Mul(matt x,matt y) //矩阵乘 
{
    matt c;
    for(ll i=1;i<=len;i++)
      for(ll j=1;j<=len;j++)
        c.mt[i][j]=0;
    for(ll i=1;i<=len;i++)
      for(ll j=1;j<=len;j++)
        for(ll k=1;k<=len;k++)
          c.mt[i][j]=c.mt[i][j]%mod+x.mt[i][k]*y.mt[k][j]%mod;
    return c; 
}
 
matt pow(matt x,ll y) //矩阵快速幂 
{
    matt ans=e;
    while(y)
    {
        if(y&1)
         ans=Mul(ans,x);  
        x=Mul(x,x);
        y>>=1;
    }
    return ans;
}
 
//填写矩阵 
ll work(){
	ll i,j;
	for(i=1;i<=len;i++)
        e.mt[i][i]=1;
    memset(a.mt,0,sizeof(a.mt));
    for(i=1;i<=len;i++){
    	if(i==1){
    		a.mt[1][1]=1; 
    		for(j=2;j<=len;j++){
    			a.mt[1][j]=p[j-2];
    		}
    		continue;
    	}
    	if(i==2){
    		for(j=2;j<=len;j++){
    			a.mt[2][j]=p[j-2];
    		}
    		continue;
    	}
    	a.mt[i][j-1]=1;
    }
    matt al=pow(a,n-2*k);
    ll xx[maxn],x[maxn],ans=0;
    for(i=1;i<=k;i++)xx[i]=f[k+i];xx[k+1]=sum[2*k];
    for(i=1;i<=len;i++)x[len-i+1]=xx[i];
	for(i=1;i<=len;i++){
		ans+=al.mt[1][i]*x[i];
		ans%=mod;
	}
    return ans;
}


int main(){
    ll cas;
    read(cas);
    while(cas--){
        read(k);read(n);len=k+1;
		for(ll i=1;i<=2*k;i++)read(f[i]);
		memset(sum,0,sizeof(sum));
		for(ll i=1;i<=2*k;i++){
			sum[i]=sum[i-1]+f[i];
			sum[i]%=mod;
		}
		if(n<=2*k){
			cout<<sum[n]<<endl;
			continue;
		}
		solve();
        gauss_elimin();
        cout<<work()<<endl;
    }
    return 0;
}
发布了27 篇原创文章 · 获赞 11 · 访问量 3590

猜你喜欢

转载自blog.csdn.net/Megurine_Luka_/article/details/100905475