TOJ4277: Sequence 组合数学

4277: Sequence 

Time Limit(Common/Java):2000MS/6000MS     Memory Limit:65536KByte
Total Submit: 39            Accepted:11

Description

 

YXH is very fond of the sequence. One day he found a very interesting sequence.
At time T, a sequence A is
A(1),A(2),...,A(n)
After one second (at time T + 1), the sequence will become
A(1),A(2)+2A(1),A(3)+2A(2)+3A(1),…,A(n)+2A(n-1)+...+nA(1)
YXH wants to know the sequence at time K. Can you solve this problem?

Input

 

There are multiple test cases.
For each case, the first line contains a number N indicating the length of the sequence. The second line contains N numbers indicating the sequence in time 0. The third line contains a number K as description above.

1 <= N <= 300, 1 <= K <= 1,000,000,000
The value of each number in the sequence will not exceed 300.

Output

 

For each case, print the sequence at time K in one line. Since the answer could be very large, you should output the answer module 1,000,000,007

Sample Input

Sample Output

Source

2012年武汉大学第六届E鸣杯程序设计竞赛

看似矩阵快速幂,但是这个矩阵是300*300的矩阵,很容易就爆炸了,因为矩阵乘法是n^3的,再做快速幂是logk

这个矩阵的构造应该不算是很难吧,就是填1到n,然后斜线上的值是一样的

矩阵快速幂代码

 

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
const int N=305,MD=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-9,e=exp(1),PI=acos(-1.);
typedef long long ll;
int G;
struct MX
{
    int v[N][N];
    void O()
    {
        memset(v,0,sizeof v);
    }
    void E()
    {
        memset(v,0,sizeof v);
        for(int i=0; i<G; i++)
            for(int j=i;j<G;j++)v[i][j]=j-i+1;
    }
    void P()
    {
        for(int i=0; i<G; i++)
            for(int j=0; j<G; j++)printf(j==G-1?"%d\n":"%d ",v[i][j]);
    }
    MX operator+(const MX &b) const
    {
        MX c;
        c.O();
        for(int i=0; i<G; i++)
            for(int j=0; j<G; j++)c.v[i][j]=v[i][j]+b.v[i][j];
        return c;
    }
    MX operator*(const MX &b)const
    {
        MX c;
        c.O();
        for(int k=0; k<G; k++)
            for(int i=0; i<G; i++)
                if(v[i][k])for(int j=0; j<G; j++)c.v[i][j]=(c.v[i][j]+1LL*v[i][k]*b.v[k][j]%MD)%MD;
        return c;
    }
     MX operator^(int p)const
    {
        MX y,x;
        y.E(),memcpy(x.v,v,sizeof(v));
        for(; p; x=x*x,p>>=1)if(p&1)y=y*x;
        return y;
    }
} a,ans;
int main()
{
    //ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,k;
    while(~scanf("%d",&n))
    {
        G=n;
        a.O();
        for(int i=0; i<n; i++)scanf("%d",&a.v[0][i]);
        scanf("%d",&k);
        ans.E();
        ans=ans^(k-1);
        ans=a*ans;
        for(int i=0; i<n; i++)printf(i==G-1?"%d\n":"%d ",ans.v[0][i]);
    }
    return 0;
}

 

接下来进入找规律环节,找个p的规律啊。

因为我比较傻,还以为这个还是和快速幂的拼凑有关的,就只去了打了2 4  16 256的值,很难发现规律

然后我每个都打了一次

k=0显而易见 1 2 3 4 5 6

k=1  1 2 ...  

k=2  1 4 ...

反正你很快会发现就是这一项是C(i,2k-1+i)

所以你很想到组合数

但是直接求组合数可行么,是可行的,当然k很大,你不会玩

其实就是乘上新加的数,除以i,当然这个题目要除以逆元

#include<stdio.h>
const int N=305,MD=1e9+7;
int a[N],b[N],v[N],n,k,i,j;
int main()
{
    v[1]=b[0]=1;
    for(int i=2;i<N;i++)v[i]=1LL*v[MD%i]*(MD-MD/i)%MD;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=0; i<n; i++)scanf("%d",&a[i]);
        scanf("%d",&k);
        long long t=2*k;
        for(i=1; i<n; i++,t++)b[i]=t*b[i-1]%MD*v[i]%MD;
        for(i=n-1; i>0; i--)
            for(j=1; j<=i; j++)a[i]=(a[i]+b[j]*1LL*a[i-j])%MD;
        for(i=0; i<n; i++)printf(i==n-1?"%d\n":"%d ",a[i]);
    }
    return 0;
}

 

 

 

posted @ 2018-08-09 16:04  暴力都不会的蒟蒻  阅读(284)  评论(0编辑  收藏  举报