CF 223C

题意:给出一个数列a[n],规定一种操作:用其前n项和s[n]覆盖a[n],一共操作k次,输出数列a。1<=n<=2000,0<=k<=109,0<=ai<=109

思路:首选想到用矩阵快速幂做,而且针对大数k,我设计了一种方案:储存20~229(230略>109),把k化为2进制,按位&1,是1就加上相应的2^n,很方便有木有?!无奈其复杂度是O(n3)的,当n=200时就差不多TLE了;而且也很耗空间。

由此得出结论:当对数列进行不规则变换时,用矩阵做;当进行纯洁的变换时,还是找规律吧O__O"…

最后找到的规律为:Sn=sum(Xn-i * ai),i=1<=n。Xn-i = C(k-1+n-i,k-1)。

 1 //  2013-08-01 20:36:10
 2 //  0KB 92ms 1060B
 3 //  by Siriuslzx
 4 #include <stdio.h>
 5 #include <string.h>
 6 typedef long long LL;
 7 
 8 const int N = 2005;
 9 const int Mod = 1000000007;
10 LL a[N],x[N],iv[N];
11 
12 void gcd(LL a, LL b, LL&d, LL &x, LL &y){
13     if(!b){d = a, x = 1, y = 0;}
14     else{
15         gcd(b, a%b, d, y, x);
16         y -= x*(a/b);
17     }
18 }
19 LL inv(LL a, LL n){
20     LL d, x, y;
21     gcd(a, n, d, x, y);
22     return d == 1 ? (x+n)%n : -1;
23 }
24 void init(int n, int k){
25     x[0] = 1;
26     for(int i = 1; i < n; i++)
27         x[i] = x[i-1]*(k-1+i)%Mod*iv[i]%Mod;
28 }
29 
30 int main(){
31     int n,k,i,j;
32     LL sum;
33     for(i = 1; i < N; i++)
34         iv[i] = inv(i, Mod);
35     scanf("%d%d",&n,&k);
36     for(i = 1; i <= n; i++)
37         scanf("%I64d",&a[i]);
38 //  其实当k==0时依然兼容,只是再算感觉浪费
39     if(!k){
40         for(i = 1; i < n; i++)
41             printf("%I64d ",a[i]);
42         printf("%I64d
",a[n]);
43         return 0;
44     }
45 //  后来把中间这段掐了再交,时间还是一样的
46     init(n,k);
47     for(i = 1; i <= n; i++){
48         sum = 0;
49         for(j = 1; j <= i; j++)
50             sum = (sum + x[i-j]*a[j]%Mod)%Mod;
51         if(i != n)
52             printf("%I64d ",sum);
53         else printf("%I64d
",sum);
54     }
55     return 0;
56 }

 通过做这题得到的一个结论:以1为首项的k阶等差数列,An = C(k+n-1,k)。

原文地址:https://www.cnblogs.com/lzxskjo/p/3231261.html