【NOIP2016提高A组模拟7.21】Clock Sequence

来源:互联网 发布:centos安装kafka 编辑:程序博客网 时间:2024/06/05 17:12

Description

科学家温斯顿定义了一个无限重复的数列:1234321234321234321……,并将其称为时钟序列。
他发现可以将数列人为分成几段:
1, 2, 3, 4, 32, 123, 43, 2123, 432, 1234, 32123, …
他又定义了新数列中第n项为Vn,这样分组能够满足Vn的数字和等于n。例如,V2=2,V7=43,V11=32123。
请帮助他求出数列V的前n项和。

Input

第一行一个正整数,表示n。

Output

第一行一个整数,表示数列V前n项和对123454321取模后的值。

Sample Input

输入1:
11
输入2:
1000

Sample Output

输出1:
36120
输出2:
18232686

Data Constraint

Subtask1[20pts]:N<=40
Subtask2[20pts]:N<=1000
Subtask3[60pts]:N<=10^14

Solution

这题奇奇怪怪
40分是显然的,直接n2暴力就可以得到
然后你需要打个表,就可以发现,数字是每15个一组的
比如说
1->1
2->2
3->3
4->4
5->32

15->1 23432
16->1 234321

30->123432 123432
31->1 234321 234321

46->1 234321 234321 234321

发现了什么?
每个数都是AB…的形式的
比如说每组的第一个数,就是1、16、31、46等
A=1,B=234321
16时是AB
31时是ABB
46时是ABBB
发现这个规律后,就可以打一个15的表,后面的数用矩阵乘法求出
当然,也可以用数学方法如等比数列的方式,但是由于mo数不是质数,要用exgcd,懒得打,而且矩阵乘法方便很多

Code

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define mo 123454321#define ll long long#define M 1000000using namespace std;ll A[16]={0,1,2,3,4,32,123,43,2123,432,1234,32123,43212,34321,23432,123432};ll B[16]={0,234321,343212,432123,321234,123432,432123,212343,432123,123432,321234,432123,343212,234321,123432,123432};ll a[3][3]={M,0,M,1,1,1,0,0,1},b[3][3],c[3][3];ll n,ans=0;void cl(){    fo(i,0,2) fo(j,0,2) c[i][j]=a[i][j],a[i][j]=0;}void ch(){    cl();    fo(i,0,2) fo(j,0,2) fo(k,0,2) a[i][k]=(a[i][k]+c[i][j]*c[j][k])%mo;}void ch2(){    cl();    fo(i,0,2) fo(j,0,2) fo(k,0,2) a[i][k]=(a[i][k]+c[i][j]*b[j][k])%mo;}void mi(ll x){    if(x<=1) return;    fo(i,0,2) fo(j,0,2) b[i][j]=a[i][j];    mi(x/2);    ch();    if(x%2==1) ch2();}int main(){    scanf("%lld",&n);    if(n<15)     {        fo(i,1,n) ans=(ans+A[i])%mo;        printf("%lld\n",ans);return 0;    }    ll jy1=n/15,jy2=n%15;    mi(jy1-1);    if(jy1==1)    {        memset(a,0,sizeof(a));        a[0][0]=a[1][1]=a[2][2]=1;    }    fo(i,0,2) fo(j,0,2) b[i][j]=a[i][j];    fo(i,1,15)    {        memset(a,0,sizeof(a));        a[0][0]=A[i];a[0][1]=B[i];a[0][2]=A[i];        ch2();        ans=(ans+a[0][2])%mo;        if(i<=jy2) ans=(ans+a[0][0]*M+a[0][1])%mo;    }    printf("%lld\n",ans);}