• 【积累】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("
    ");
        }
        */
        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("
    ");
            
            
            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("##
    ");
    //        for(i=0;i<2*k;i++)
    //        {
    //            for(j=0;j<2*k;j++)
    //                printf("%lld ",S[i][j]);
    //            printf("
    ");
    //        }printf("##
    ");
            
            
            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("
    ");
            }//A+A^2+……+A^N-k 
            
            for(i=0;i<k;i++)
            {
                ans=(ans+A[0][i]*f[k-i]%mod)%mod;
            }
            printf("%lld
    ",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
    ",&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
    ",ans);
        }
    }

    哎....

  • 相关阅读:
    [HNOI2014]江南乐
    烦人的数学作业(数位dp)
    http2.0请求springboot接口
    01背包动态规划
    坑点总结
    [机房测试] 堆石子
    [机房测试] 出租车
    [机房测试] 下棋
    [机房测试] number
    [CSP-S2019] 树的重心
  • 原文地址:https://www.cnblogs.com/kkkek/p/11520413.html
Copyright © 2020-2023  润新知