【BZOJ3453】XLkxc [拉格朗日插值法]

XLkxc

Time Limit: 20 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

Description

  给定 k,a,n,d,p
  f(i)=1^k+2^k+3^k+......+i^k
  g(x)=f(1)+f(2)+f(3)+....+f(x)
  求(g(a)+g(a+d)+g(a+2d)+......+g(a+nd))mod p

Input

  第一行数据组数,(保证小于6)
  以下每行四个整数 k,a,n,d

Output

  每行一个结果。

Sample Input

  5
  1 1 1 1
  1 1 1 1
  1 1 1 1
  1 1 1 1
  1 1 1 1

Sample Output

  5
  5
  5
  5
  5

HINT

  1<=k<=123
  0<=a,n,d<=123456789
  p==1234567891

Main idea

  给定k,a,n,d,求

Solution

  我们可以令

  然后推一波式子,再令

  那么显然有

  然后我们通过若干次差分,发现g在差分k+3次时全为0,那么g就是一个k+2次多项式;f在差分k+5次时全为0,那么f就是一个k+4次多项式

  我们通过拉格朗日插值法插g,得到k+5个f的值,然后再插值f就可以得到答案了。

Code

 1 #include<iostream>  
 2 #include<string>  
 3 #include<algorithm>  
 4 #include<cstdio>  
 5 #include<cstring>  
 6 #include<cstdlib>  
 7 #include<cmath>  
 8 using namespace std;  
 9 typedef long long s64;
10 const int ONE=1001;
11 const s64 MOD=1234567891;
12 
13 int T;
14 int k,a,n,d;
15 int g[ONE],f[ONE];
16 int inv[ONE],U[ONE],Jc[ONE];
17 int pre[ONE],suc[ONE];
18 
19 int get() 
20 {
21         int res=1,Q=1;  char c;
22         while( (c=getchar())<48 || c>57)
23         if(c=='-')Q=-1;
24         if(Q) res=c-48; 
25         while((c=getchar())>=48 && c<=57) 
26         res=res*10+c-48; 
27         return res*Q; 
28 }
29 
30 int Quickpow(int a,int b)
31 {
32         int res=1;
33         while(b)
34         {
35             if(b&1) res=(s64)res*a%MOD;
36             a=(s64)a*a%MOD;
37             b>>=1;
38         }
39         return res;
40 }
41 
42 int P(int k,int i)
43 {
44         if((k-i)&1) return -1+MOD;
45         return 1;
46 }
47 
48 namespace First
49 {
50         void Deal_jc(int k)
51         {
52             Jc[0]=1;
53             for(int i=1;i<=k;i++) Jc[i]=(s64)Jc[i-1]*i%MOD;
54         }
55         
56         void Deal_inv(int k)
57         {
58             inv[0]=1;    inv[k]=Quickpow(Jc[k],MOD-2);
59             for(int i=k-1;i>=1;i--) inv[i]=(s64)inv[i+1]*(i+1)%MOD;
60         }
61 }
62 
63 int Final(int f[],int n,int k)
64 {
65         pre[0]=1;    for(int i=1;i<=k;i++) pre[i]=(s64)pre[i-1] * (n-i+MOD) % MOD;
66         suc[0]=1;    for(int i=1;i<=k;i++) suc[i]=(s64)suc[i-1] * (s64)(n-k+i-1+MOD) % MOD;
67         
68         s64 Ans=0;
69         for(int i=1;i<=k;i++)
70         {
71             int Up=   (s64) pre[i-1]*suc[k-i] % MOD * f[i] % MOD;
72             int Down= (s64) inv[i-1]*inv[k-i] % MOD;
73             
74             Ans=(s64)(Ans + (s64) Up*Down % MOD * P (k,i) %MOD) % MOD;
75         }
76         
77         return Ans;
78 }
79 
80 int main()
81 {      
82         First::Deal_jc(150);    First::Deal_inv(150);
83         T=get();
84         while(T--)
85         {
86             k=get();    a=get();    n=get();    d=get();
87             
88             for(int i=0;i<=k+3;i++) g[i]=Quickpow(i,k);
89             for(int i=1;i<=k+3;i++) g[i]=((s64)g[i-1]+g[i])%MOD;
90             for(int i=1;i<=k+3;i++) g[i]=((s64)g[i-1]+g[i])%MOD;
91             for(int i=0;i<=k+5;i++)
92             f[i]=((s64)f[i-1]+Final(g,(a+(s64)i*d)%MOD,k+3)) % MOD;
93             
94             printf("%d
",Final(f,n,k+5)%MOD);
95         }
96 }    
View Code
原文地址:https://www.cnblogs.com/BearChild/p/6424353.html