BZOJ-3231 递归数列 矩阵连乘+快速幂

题不是很难,但是啊,人很傻啊。。。机子也很鬼畜啊。。。

3231: [Sdoi2008]递归数列
Time Limit: 1 Sec Memory Limit: 256 MB
Submit: 569 Solved: 241
[Submit][Status][Discuss]

Description
一个由自然数组成的数列按下式定义:
对于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的余数的值。

Input
由四行组成。
第一行是一个自然数k。
第二行包含k个自然数b1, b2,…,bk。
第三行包含k个自然数c1, c2,…,ck。
第四行包含三个自然数m, n, p。

Output
仅包含一行:一个正整数,表示(am + am+1 + am+2 + … + an) mod p的值。

Sample Input
2
1 1
1 1
2 10 1000003

Sample Output
142

HINT
对于100%的测试数据:
1<= k<=15
1 <= m <= n <= 1018

Source

第一次调试:矩阵都是【1001】【1001】虽然很多余,但是理论上并没错,但是机子low每次调用到就炸....
第二次调试:矩阵的初始化调上次时不小心删了....又WA....
第三次调试:出现负数,以为爆longlong果断+快速乘,still booming
然后发现是最后做前缀和减法时..可能减到负了.....
于是A之,带快速乘版本1600MS+,删之160MS+....珍爱生命远离快速乘TAT

构造的矩阵如下:
这里写图片描述
S为前缀和…最后只需要进行前缀和相减即可…

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
long long read()
{
    long long x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

long long k,m,n,p;
long long s=0;
long long cc[50],bb[50];
struct Mat{
    long long da[50][50];
    Mat(){memset(da,0,sizeof(da));}   
};

//long long quick_mul(long long x,long long y)
//{
//    if (y==0) return 0;
//    if (y==1) return x%p;
//    long long re;
//    re=quick_mul(x,y>>1);
//    if ((y&1)==1) return (re+re+x)%p;
//             else return (re+re)%p;
//}

Mat mul(Mat A,Mat B)
{
    Mat C;
    for (int i=1; i<=k+1; i++)
        for (int j=1; j<=k+1; j++)
            for (int kk=1; kk<=k+1; kk++)
                C.da[i][j]=(C.da[i][j]+(A.da[i][kk]*B.da[kk][j])%p)%p;
    return C;
} 

Mat quick_pow(Mat A,long long x)
{
    Mat re;
    for (int i=1; i<=k+1; i++) re.da[i][i]=1;
    for (long long i=x; i; i>>=1,A=mul(A,A))
        if (i&1) re=mul(re,A);
    return re;
}

Mat a;
Mat b;
void init()
{
    for (int i=1;i<=k;i++)  a.da[i][1]=a.da[i][k+1]=cc[i];
    for (int i=2;i<=k;i++)  a.da[i-1][i]=1;
    a.da[k+1][k+1]=1;
    for (int i=1;i<=k;i++)  b.da[1][i]=bb[k-i+1];
    b.da[1][k+1]=s;
}

long long work(long long x)
{
    if (x==0) return b.da[1][k+1];
    Mat re;
    re=quick_pow(a,x);
    re=mul(b,re);
    return re.da[1][k+1];
}

int main()
{
    k=read();
    for (int i=1; i<=k; i++) bb[i]=read();
    for (int i=1; i<=k; i++) cc[i]=read();   
    m=read(),n=read(),p=read();
    for (int i=1; i<=k; i++) bb[i]%=p,s=(s+bb[i])%p,cc[i]%=p;
    long long ans=0;
    if (n<=k) 
        {
            for (int i=m; i<=n; i++) ans=(ans+bb[i])%p;
            printf("%lld\n",ans);
            return 0;
        }
    init();
    ans=work(n-k);
    if (m>k) ans=(ans-work(m-k-1))%p;
        else for (int i=1; i<m; i++) ans=(ans-bb[i])%p;
    ans=(ans+p)%p;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2016-02-27 19:57  DaD3zZ  阅读(293)  评论(0编辑  收藏  举报