题目描述
一个由自然数组成的数列按下式定义:
对于i <= k:ai = bi
对于i > k: ai = c1ai-1 + c2ai-2 + … + ckai-k
其中bj 和 cj (1<=j<=k)是给定的自然数。写一个程序,给定自然数m <= n, 计算am + am+1 + am+2 + … + an, 并输出它除以给定自然数p的余数的值。
输入输出格式
输入格式:
输入文件spp.in由四行组成。
第一行是一个自然数k。
第二行包含k个自然数b1, b2,…,bk。
第三行包含k个自然数c1, c2,…,ck。
第四行包含三个自然数m, n, p。
输出格式:
输出文件spp.out仅包含一行:一个正整数,表示(am + am+1 + am+2 + … + an) mod p的值。
输入输出样例
输入样例#1:
2
1 1
1 1
2 10 1000003
输出样例#1:
142
说明
对于100%的测试数据:
1<= k <=15
1 <= m <= n <= 1018
对于20%的测试数据:
1<= k <=15
1 <= m <= n <= 106
对于30%的测试数据:
k=1 1 <= m <= n <= 1018
对于所有测试数据:
0<= b1, b2,… bk, c1, c2,…, ck<=109
1 <= p <= 108
这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const int N=20;
int k;
LL n,mm,mod;
LL b[N],c[N];
LL tot=0;
struct node{
LL m[N][N];
node operator *(const node &a) const{
node ans;
for (int i=1;i<=k;i++)
for (int j=1;j<=k;j++)
{
ans.m[i][j]=0;
for (int l=1;l<=k;l++)
ans.m[i][j]=(ans.m[i][j]+m[i][l]*a.m[l][j])%mod;
}
return ans; ///
}
void clear()
{
memset(m,0,sizeof(m));
}
LL KSM(LL pp)
{
LL p;
if (pp<=k) //用不到矩乘
{
LL an=0;
for (int i=1;i<=pp;i++) //直接暴力
an=(an+b[i])%mod;
return an%mod;
}
p=pp-k; //真心。。对样例调一调就好了
node ans=(*this),a=(*this);
while (p)
{
if (p&1)
ans=ans*a;
a=a*a;
p>>=1;
}
LL r=0;
for (int i=1;i<k;i++)
r=(r+(ans.m[i][k]*b[k-i])%mod)%mod; //计算前缀和
r=(r+(tot*ans.m[k][k])%mod)%mod;
return r; //sum
}
};
int main()
{
scanf("%d",&k);
for (int i=1;i<=k;i++) scanf("%lld",&b[i]);
for (int i=1;i<=k;i++) scanf("%lld",&c[i]);
scanf("%lld%lld%lld",&mm,&n,&mod);
for (int i=1;i<=k;i++) tot=(tot+b[i]%mod)%mod; //tot前缀和
node m,t;
m.clear(); t.clear();
for (int i=1;i<=k;i++) //矩阵的初始值
{ //在矩阵中我们要维护一个前缀和
m.m[i][1]=c[i];
m.m[i][k+1]=c[i];
t.m[i][1]=c[i];
t.m[i][k+1]=c[i];
}
for (int i=1;i<k;i++) m.m[i][i+1]=1,t.m[i][i+1]=1;
m.m[k+1][k+1]=1;
t.m[k+1][k+1]=1;
k++;
LL an=0;
an+=m.KSM(n);
an-=t.KSM(mm-1);
printf("%lld",(an+mod)%mod); //题目有漏洞,在最后的%处理时要先+mod再%
return 0;
}