zoukankan      html  css  js  c++  java
  • P1707 刷题比赛

    P1707 刷题比赛

      • 10通过
      • 38提交
    • 题目提供者nodgd
    • 标签倍增递推矩阵洛谷原创
    • 难度提高+/省选-

    提交该题 讨论 题解 记录

    最新讨论

    题目背景

    nodgd是一个喜欢写程序的同学,前不久洛谷OJ横空出世,nodgd同学当然第一时间来到洛谷OJ刷题。于是发生了一系列有趣的事情,他就打算用这些事情来出题恶心大家……

    题目描述

    洛谷OJ当然算是好地方,nodgd同学打算和朋友分享一下。于是他就拉上了他的朋友Ciocio和Nicole两位同学一起刷题。喜欢比赛的他们当然不放过这样一次刷题比赛的机会!

    在第1天nodgd,Coicoi,Nicole都只做了1道题。

    在第2天nodgd,Coicoi,Nicole都只做了3道题。

    他们都有着严格的刷题规则,并且会在每一天都很遵守规则的刷一定量的题。

    (1)nodgd同学第k+2天刷题数量a[k+2]=p*a[k+1]+q*a[k]+b[k+1]+c[k+1]+r*k^2+t*k+1;

    (2)Ciocio同学第k+2天刷题数量b[k+2]=u*b[k+1]+v*b[k]+a[k+1]+c[k+1]+w^k;

    (3)Nicole同学第k+2天刷题数量c[k+2]=x*c[k+1]+y*c[k]+a[k+1]+b[k+1]+z^k+k+2;

    (以上的字母p,q,r,t,u,v,w,x,y,z都是给定的常数,并保证是正整数)

    于是他们开始了长时间的刷题比赛!一共进行了N天(4<=N<=10^16)

    但是时间是可贵的,nodgd想快速知道第N天每个人的刷题数量。不过nodgd同学还有大量的数学竞赛题、物理竞赛题、英语竞赛题、美术竞赛题、体育竞赛题……要做,就拜托你来帮他算算了。

    由于结果很大,输出结果mod K的值即可。

    输入输出格式

    输入格式:

    第一行两个正整数N,K。(4<=N<=10^16,2<=K<=10^16)

    第二行四个正整数p,q,r,t。

    第三行三个正整数u,v,w。

    第四行三个正整数x,y,z。

    (保证p,q,r,t,u,v,w,x,y,z都是不超过100的正整数)

    输出格式:

    共三行,每行一个名字+一个空格+一个整数。依次是nodgd,Ciocio,Nicole和他们在第N天刷题数量mod K的值。

    输入输出样例

    输入样例#1:
    4 10007
    2 1 1 1
    2 2 3
    1 1 2
    输出样例#1:
    nodgd 74
    Ciocio 80
    Nicole 59

    说明

    矩阵乘法。

    注意,中间相乘过程可能会比64位长整型的数据范围还要大。

    看到数据范围很大,之后异想天开,以为一定会答案循环,再加上快速幂,最多也只是50分。

    #include<cstdio>
    #include<iostream>
    #define ll long long
    using namespace std;
    const int N=2e5+100;
    ll n,mod;
    ll a[N]={0,1,3};
    ll b[N]={0,1,3};
    ll c[N]={0,1,3};
    ll kpow(ll a,ll p){
        ll ans=1;
        for(;p;p>>=1,a=(a*a)%mod) if(p&1) ans=(ans*a)%mod;
        return ans;
    }
    int main(){
        //freopen("sh.txt","r",stdin);
        int p,q,r,t,u,v,w,x,y,z;ll ma(0),mb(0),mc(0);bool fa(0),fb(0),fc(0);
        cin>>n>>mod;
        cin>>p>>q>>r>>t>>u>>v>>w>>x>>y>>z;
        if(mod==1){printf("nodgd 0
    Ciocio 0
    Nicole 0
    ");return 0;} 
        if(n==1){printf("nodgd 1
    Ciocio 1
    Nicole 1
    ");return 0;}
        if(n==2){printf("nodgd %d
    Ciocio %d
    Nicole %d
    ",3%mod,3%mod,3%mod);return 0;}
        for(ll i=3;i<=n;i++){
            a[i]=(p*a[i-1]%mod+q*a[i-2]%mod+b[i-1]+c[i-1]+r%mod*kpow((i-2)%mod,2)%mod+t*(i-2)%mod+1)%mod;
            b[i]=(u*b[i-1]%mod+v*b[i-2]%mod+a[i-1]+c[i-1]+kpow(w%mod,(i-2))%mod)%mod;
            c[i]=(x*c[i-1]%mod+y*c[i-2]%mod+a[i-1]+b[i-1]+kpow(z%mod,(i-2))%mod+i)%mod;
            if(a[i]==a[2]&&a[i-1]==a[1]){ma=i-2;fa=1;}
            if(b[i]==b[2]&&b[i-1]==b[1]){mb=i-2;fb=1;}
            if(c[i]==c[2]&&c[i-1]==c[1]){mc=i-2;fc=1;}
            if(fa&&fb&&fc) break;
        }
        if(fa&&fb&&fc){
            cout<<"nodgd "<<a[n%ma]<<endl;
            cout<<"Ciocio "<<b[n%mb]<<endl;
            cout<<"Nicole "<<c[n%mc]<<endl; 
        }
        else{
            cout<<"nodgd "<<a[n]<<endl;
            cout<<"Ciocio "<<b[n]<<endl;
            cout<<"Nicole "<<c[n]<<endl;  
        }
        return 0;
    }

    看到标签,“矩阵乘法”,去网上看了看矩阵乘法

    附上AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    ll n,mod,p,q,r,t,u,v,w,x,y,z;
    ll f[12][12],a[12][12];
    ll slow_mul(ll a,ll b){
        ll ans=0;
        while(b){
            if(b&1){
                b--;ans+=a;ans%=mod;
            }
            a<<=1;a%=mod;b>>=1;
        }
        return ans;
    }
    void mul(ll a[12][12],ll b[12][12]){
        ll c[12][12];memset(c,0,sizeof(c));
        for(int i=1;i<=11;i++)
            for(int j=1;j<=11;j++)
                for(int k=1;k<=11;k++)
                    c[i][j]=(c[i][j]+slow_mul(a[i][k],b[k][j]))%mod;
        for(int i=1;i<=11;i++)
            for(int j=1;j<=11;j++)
                a[i][j]=c[i][j];
    }
    int main()
    {
        cin>>n>>mod>>p>>q>>r>>t>>u>>v>>w>>x>>y>>z;n-=2;
        f[1][1]=f[1][3]=f[1][5]=3;f[1][2]=f[1][4]=f[1][6]=1;
        f[1][7]=f[1][8]=f[1][9]=1;f[1][10]=w;f[1][11]=z;
        a[1][1]=p;a[2][1]=q;a[7][1]=r;a[8][1]=t;a[3][3]=u;
        a[4][3]=v;a[5][5]=x;a[6][5]=y;a[9][5]=a[8][7]=2;
        a[10][10]=w;a[11][11]=z;
        a[1][2]=a[1][3]=a[1][5]=a[3][1]=a[3][4]=a[3][5]=1;
        a[5][1]=a[5][3]=a[7][7]=a[8][5]=a[8][8]=a[9][1]=1;
        a[9][7]=a[9][8]=a[9][9]=a[10][3]=a[11][5]=a[5][6]=1;
        while(n){
            if(n&1)mul(f,a);
            mul(a,a);n>>=1;
        }
        cout<<"nodgd"<<" "<<f[1][1]<<endl;
        cout<<"Ciocio"<<" "<<f[1][3]<<endl;
        cout<<"Nicole"<<" "<<f[1][5]<<endl;
        return 0;
    }
  • 相关阅读:
    scrapy 链接数据库创表语句
    工作问题总结
    插入排序
    centos6.5 安装python2.7.5
    冒泡排序
    [Python笔记]第十篇:模块续
    [Python笔记]第九篇:re正则表达式
    [Python笔记]第八篇:模块
    [Python笔记]第六篇:文件处理
    [Python笔记]第五篇:递归
  • 原文地址:https://www.cnblogs.com/shenben/p/5741977.html
Copyright © 2011-2022 走看看