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\nCiocio 0\nNicole 0\n");return 0;}
    if(n==1){printf("nodgd 1\nCiocio 1\nNicole 1\n");return 0;}
    if(n==2){printf("nodgd %d\nCiocio %d\nNicole %d\n",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;
}
时间: 2024-10-08 17:36:45

P1707 刷题比赛的相关文章

洛谷 1707 刷题比赛

/* 矩阵稍微有点难搞 不过也是可以推出来 注意防爆... */ #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&

ubuntu下vim配置(刷题和比赛两套)

1. 平时刷题练习使用 "mswin.vim 插件提供windows下的编辑快捷键功能 source $VIMRUNTIME/mswin.vim behave mswin set nu set history=1000000 set tabstop=4 set shiftwidth=4 set smarttab set cindent set nobackup set noswapfile set mouse=a colo torte "设置字体 set guifont=DejaVuS

刷题计划

我很后悔这一年来被我浪费过的每分每秒,我已经不想再浪费时间了. 平时不好好刷题还想着打比赛? 今年的目标就是刷完紫书第七章的搜索,第八章的贪心,第九章的dp,然后每次的cf补题尽量补到div2的DE题,如果时间有剩余,就学AC自动机等一些数据结构吧. 第一阶段:紫书ch7-ch9  时间11月末-12月31号 第二阶段  训练指南选择性的补充知识点,同时打一些5个小时比赛+补题  时间1月-2月 第三阶段  区域赛真题组队训练

比较好的刷题网站推荐

1.Leetcode鼎鼎大名的Leetcode,据不完全统计在上面被刷过的题可以围绕地球三圈.(没说赤道哈,就是这么严谨.)总之,很多国内外的码农在上面刷题.难度从easy到hard都有,而且覆盖面极广.现在还增加了数据库和shell,相匹配的论坛也可以多看看.很锻炼和国外码农沟通的能力,对于以后去混Github也有好处. 特点:各种语言支持很广泛,题型覆盖很广,测试数据集较弱. 2.Codility同样一家著名的国外刷题网站.和Leetcode不同,它是专门帮各大软件公司笔试用的,只是副业提供

国内有哪些好的刷题网站?

http://www.zhihu.com/question/25574458 Luau Lawrence,Data Mining 弱鸡 / [email protected] 温梦强.石一帆.知乎用户 等人赞同 - Welcome To PKU JudgeOnline 北京大学的Online Judge.POJ上面的题目有点老了,但好处是做的人多,经典算法题多,解题报告也多,适合上手.- ZOJ :: Home 浙江大学的Online Judge.ZOJ用的不多,但为数不多的几次体验好像都还可以

ife任务刷题总结(一)-css reset与清除浮动

本文同时发布于本人的个人网站www.yaoxiaowen.com 百度创办的前端技术学院,是一个面向大学生的前端技术学习平台.虽然只有大学生才有资格报名,提交代码进行比赛排名.但是这并不妨碍我们这些初学者也可以按照他们的任务列表,进行刷题.虽然ife名义上是针对初学者,但是我看了一下任务列表,那些任务还并不是那么简单.所以很适合初学者把任务刷一遍,我觉的,把这些任务都刷完,那么前端算是入门了. 对于代码学习来讲,除了实际的去敲,还有其他更好的学习方法吗?因此我计划按照ife的任务都刷一遍,代码提

不知道要过多久,我才能返回到九月份刷题的模样!!!

不知道要过多久,我才能返回到九月份刷题的模样!!! 比完赛后,在家里待了几天,来到学校后,我就天天刷题 ,那个时候不明白自己哪里来的平静的心态,或者是比赛的氛围所影响,那个时候,课表上的课没有现在这么满,一个星期有两三个下午是没有课的,有两三个上午的第一二节课是没有课的,那些没有课的日子,我一二节课没有课就是6点多起床,然后七点钟就到610开始做题,下午没有课,我午休就坐在610,困了就趴一会儿,晚自习,记得第一个星期还要上晚息,于是我就是等学习部查完到就来610坐着刷题,那个时候不知道自己何来

雅虎刷题狂人曹鹏:10年理论与实践结合的程序员之路

曹鹏,2006年浙江大学计算机科学专业毕业,2013年中国科学院计算机技术研究所博士毕业.博士期间研究方向为社交网络与社会计算,曾经做过搜索.话题发现.社交网络方面.推荐算法等领域的相关研究. 曾为浙江大学.浙江省大学生程序设计竞赛的命题人,是hackerrank.com.hackerearth.com和csdn英雄会.CSDN高校编程挑战的命题人,也是PAT(Programming Ability Test, http://pat.zju.edu.cn/) 的命题人.是国内ZOJ(http:/

BZOJ 刷题记录 PART 5

拖了好久才写的. [BZOJ2821]接触分块大法.这道题略有点新颖.首先我们先分块,然后统计每块中每个数出现的个数. 下面是联立各个方块,预处理出第I个方块到第J个方块出现正偶数次数的个数. for (i=1;i<=s;i++) { for (j=i;j<=s;j++) { sum[i][j]=sum[i][j-1]; for (k=a[j].l;k<=a[j].r;k++) { temp[data[k]]++; if (!(temp[data[k]]&1)) sum[i][j