【积累】The Preliminary Contest for ICPC Asia Shenyang 2019 K. Guanguan's Happy water(高斯消元)

 

 

K. Guanguan's Happy water

 

按着题解打了代码:高斯消元 和 矩阵乘法... 因为很久没有做高斯消元的题了 想着顺便做做

然后 然后没细想 就先做了 然后就T了 然后 然后发现牛客群说 题解说的时间复杂度是1e9.....

 

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
const int maxn=1e5+50;
const int mod=1e9+7;
typedef long long ll;
ll a[210],f[210];


ll kpow(ll a,ll b)
{
    ll ans=1,base=a;
    while(b)
    {
        if(b&1)ans=ans*base%mod;
        base=base*base%mod;
        b>>=1;
    }
    return ans;
}

///高斯消元模板
const int Max_M=75;       ///m个方程,n个变量
const int Max_N=75;
ll m,n;
ll Aug[Max_M][Max_N+1]; ///增广矩阵
bool free_x[Max_N];         ///判断是否是不确定的变元
ll  x[Max_N];            ///解集

/**
返回值:
-1 无解
0 有且仅有一个解
>=1 有多个解,根据free_x判断哪些是不确定的解
*/
int Gauss()
{
    int i,j;
    int row,col,max_r;
    for(row=0,col=0;row<m&&col<n;row++,col++)
    {
        max_r=row;
        for(i=row+1;i<m;i++)  ///找到当前列所有行中的最大值(做除法时减小误差)
        {
            if(fabs(Aug[i][col])-fabs(Aug[max_r][col])>0)
            max_r=i;
        }
        if(max_r!=row)            ///将该行与当前行交换
        {
            for(j=row;j<n+1;j++)
                swap(Aug[max_r][j],Aug[row][j]);
        }
        if(Aug[row][col]==0)  ///当前列row行以下全为0(包括row行)
        {
            row--;
            continue;
        }
        for(i=row+1;i<m;i++)
        {
            if(Aug[i][col]==0)continue;
            int ta=Aug[i][col]*kpow(Aug[row][col],mod-2)%mod;
            for(j=col;j<n+1;j++)
                Aug[i][j]=(Aug[i][j]-Aug[row][j]*ta%mod+mod)%mod;
        }
    }
    /*
    kkkek:
    最后化得的增广矩阵: 
    for(i=0;i<n;i++)
    {
        for(j=0;j<=n;j++)printf("%lld ",Aug[i][j]);
        printf("\n");
    }
    */
    for(i=row;i<m;i++)    ///col=n存在0...0,a的情况,无解
    {
        if(Aug[i][col])return -1;
        }
    if(row < n)     ///存在0...0,0的情况,有多个解,自由变元个数为n-row个
    {
        for(i=row-1;i>=0;i--)
        {
            int free_num=0;   ///自由变元的个数
            int free_index;     ///自由变元的序号
            for(j=0;j<n;j++)
            {
                if(Aug[i][j]!=0&&free_x[j])
                    free_num++,free_index=j;
            }
            if(free_num>1)continue;  ///该行中的不确定的变元的个数超过1个,无法求解,它们仍然为不确定的变元
            ///只有一个不确定的变元free_index,可以求解出该变元,且该变元是确定的
            int tmp=Aug[i][n];
            for(j=0;j<n;j++)
            {
                if(Aug[i][j]!=0&&j!=free_index)
                    tmp=(tmp-Aug[i][j]*x[j]%mod+mod)%mod;
            }
            x[free_index]=tmp*kpow(Aug[i][free_index],mod-2)%mod;
            free_x[free_index]=false;
        }
        return n-row;
    }
    ///有且仅有一个解,严格的上三角矩阵(n==m)
    for(i=n-1;i>=0;i--)
    {
        int tmp=Aug[i][n];
        for(j=i+1;j<n;j++)
            if(Aug[i][j]!=0)
                tmp=(tmp-Aug[i][j]*x[j]%mod+mod)%mod;
        x[i]=tmp*kpow(Aug[i][i],mod-2)%mod;
    }
    return 0;
}
///模板结束

ll S[210][210];

//矩阵乘法 
const int N=210;
ll tmp[N][N];
void multi(ll aa[][N],ll b[][N],ll n)
{
    memset(tmp,0,sizeof tmp);
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        for(int k=0;k<n;k++)
        tmp[i][j]=(tmp[i][j]+aa[i][k]*b[k][j]%mod)%mod;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        aa[i][j]=tmp[i][j];
}
ll res[N][N];
void Pow(ll aa[][N],ll b,ll n)
{
    memset(res,0,sizeof res);
    for(int i=0;i<n;i++) res[i][i]=1;
    while(b)
    {
        if(b&1)
            multi(res,aa,n);//res=res*a;复制直接在multi里面实现了;
        multi(aa,aa,n);//a=a*a
        b>>=1;
    }
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            aa[i][j]=res[i][j]%mod;
}
//


ll A[210][210]; 

 

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(Aug,0,sizeof(Aug));
        memset(x,0,sizeof(x));
        memset(free_x,0,sizeof(free_x));
        ll k,N,i,j,ans=0;
        scanf("%lld%lld",&k,&N);
        n=m=k;
        for(i=1;i<=k;i++)
        {
            scanf("%lld",&a[i]);
            f[i]=a[i];
            ans=(ans+a[i])%mod;
        }
        for(i=k+1;i<=2*k;i++)
            scanf("%lld",&f[i]);
        for(i=k;i<2*k;i++)
        {
            Aug[k-i][k]=f[i+1];
            for(j=i;j>i-k;j--)
            {
                Aug[k-i][i-j]=f[j];
            }
        }
        Gauss();
        
        
//        printf("**P:");for(i=0;i<k;i++)printf("%lld ",x[i]);printf("\n");
        
        
        memset(S,0,sizeof(S));
        for(i=0;i<k;i++)S[0][i]=x[i];
        for(i=0;i<k;i++)
        {
            if(i)S[i][i-1]=1;
            for(j=0;j<k;j++)
                S[i][i+k]=1;
                S[i+k][i+k]=1;
        }
        Pow(S,N-k+1,k*2);
        
        
//        printf("##\n");
//        for(i=0;i<2*k;i++)
//        {
//            for(j=0;j<2*k;j++)
//                printf("%lld ",S[i][j]);
//            printf("\n");
//        }printf("##\n");
        
        
        for(i=0;i<k;i++)
        {
            for(j=0;j<k;j++)
            {
                A[i][j]=S[i][j+k];
                if(i==j)A[i][j]--;
//                printf("%lld ",A[i][j]);
            }
//            printf("\n");
        }//A+A^2+……+A^N-k 
        
        for(i=0;i<k;i++)
        {
            ans=(ans+A[0][i]*f[k-i]%mod)%mod;
        }
        printf("%lld\n",ans);
    }
}

 

 

然后在我T了之后,我去看了牛客群。看到有人说:i大于k f[i]都不会变。

然后 然后就   我就大概能理解为什么这么麻烦的题这么多人过。

 

哎....

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug printf("!");
const int mod=1e9+7;
const int maxn=1e3+50;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll k,n,ans=0,i,t,r;
        scanf("%lld%lld",&k,&n);
        for(i=1;i<=k;i++)
        {
            scanf("%lld\n",&t);
            ans=(ans+t)%mod;
        }
        r=t;
        for(i=1;i<=k;i++)scanf("%d",&t);
        ans=(ans+(n-k)%mod*r)%mod;
        printf("%lld\n",ans);
    }
}

 

 

哎....

 

posted @ 2019-09-14 21:46  草丛怪  阅读(257)  评论(2编辑  收藏  举报