「FJ2015集训」热身题
「问题描述」
定义F:
F(1) = 1,
F(2) = 2,
F(n) = F(n-1) + F(n-2) (n >= 3)
定义p:
p(i) = a1*F(1)^i + a2*F(2)^i + … + ak*F(k)^i
其中k和a1…ak为常数。
现在已知k,p(1),p(2),…,p(k),求p(k+1)。为了避免高精度,所有运算都模掉M。保证F(1),…,F(n)在模质数M下两两不同,保证有唯一解。
「输入格式」
第一行,两个整数k,M。
第二行,p(1), p(2), . . . , p(k) 模 M 。
「输出格式」
输出p(k+1)模M。
「样例输入1」
3 101
5 11 29
「样例输出1」
83
「样例输入2」
4 619
5 25 125 6
「样例输出2」
30
「数据规模与约定」
对于20%的数据,k<=10
对于50%的数据,k<=100
对于100%的数据,1<=k<=4000, 3<=M<=10^9
题解
50分是裸高斯消元
lazycal:
F1 F2 … Fk
F1^2 F2^2 … Fk^2
F1^3 F2^3 … Fk^3
F1^4 F2^4 … Fk^4
…
F1^k F2^k … Fk^k
可以发现系数是有规律的。我们可以用第i行减掉第i-1行*F1,这样就可以将第1列中除了第1行的数清零。同理第2列,第3列。。。这样就可以得到一个上三角矩阵。而且第i行第j列的数为Fj*(Fj-F1)*(Fj-F2)*…*(Fj-Fi-1)。然后就可以解出a1…ak。然后算出Fk+1,得到答案。
上述做法常数实现的好的话应该可以过。
但是这题毕竟不需要求出a1…ak,所以我们可以将第k+1个方程写在最下方,也参与消元。最终最后一个方程的系数都被消为0,此时等号右边的值即为答案。
50分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#include<map> #include<set> #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #define ll long long #define inf 1000000000 #define ine(x) mul(x,P-2) using namespace std; ll read() { ll 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; } int n,P; ll f[105],tmp[105],c[105][105],a[105]; ll ans; ll mul(ll a,ll b) { ll ans=1; for(ll i=b;i;a=a*a%P,i>>=1) if(i&1)ans=ans*a%P; return ans; } void solve() { for(int i=1;i<=n;i++) { int j=i; while(c[j][i]==0)j++; for(int k=1;k<=n+1;k++)swap(c[j][k],c[i][k]); for(j=1;j<=n;j++) if(j!=i) { ll t=c[j][i]*ine(c[i][i])%P; for(int k=1;k<=n+1;k++) c[j][k]=(c[j][k]-t*c[i][k]%P+P)%P; } } } int main() { // freopen("j.in","r",stdin); // freopen("j.out","w",stdout); n=read();P=read(); f[1]=1;f[2]=2; for(int i=3;i<=n;i++)f[i]=(f[i-1]+f[i-2])%P; for(int i=1;i<=n;i++)tmp[i]=f[i]; for(int i=1;i<=n;i++)c[i][n+1]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { c[i][j]=f[j];f[j]=f[j]*tmp[j]%P; } solve(); for(int i=1;i<=n;i++) { ll b=c[i][n+1]; a[i]=b*ine(c[i][i])%P; } for(int i=1;i<=n;i++) ans=(ans+a[i]*f[i])%P; cout<<ans<<endl; // fclose(stdin); // fclose(stdout); return 0; } |
100分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include<map> #include<set> #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #define ll long long #define inf 1000000000 #define ine(x) mul(x,P-2) using namespace std; ll read() { ll 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; } int n,P; ll f[5005],tmp[5005],a[5005]; ll ans; int main() { //freopen("j.in","r",stdin); //freopen("j.out","w",stdout); n=read();P=read(); f[1]=1;f[2]=2; for(int i=3;i<=n;i++)f[i]=(f[i-1]+f[i-2])%P; for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++) for(int j=n+1;j>=i+1;j--) a[j]=(a[j]-a[j-1]*f[i]%P+P)%P; cout<<(P-a[n+1])%P<<endl; // fclose(stdin); // fclose(stdout); return 0; } |
这个封面图片也是醉了