—————————————-
概述
题目大意如下。
已知整数
n,t
以及数列
ak
,求数列
bk
的表达式使得下式恒成立:
其中,数列
ak
的递推式为:
告诉你整数
m
,输出
—————————————-
分析
我们观察这个式子:
假如这个式子恒成立,那么就说明
bk
的取值与自变量
x
无关,而只跟已知量
所以我们先考虑把已知数都放到等式的同一边,也就是将
x
带入
对于左边的 (x+t)k ,我们用二项式定理展开:
然后利用恒等变换考虑先枚举 x 的贡献:
至此,我们得到了:
这时我们发现:等式两边自变量
x
的影响都是一样的,假如我们强制令
进一步变形:
由于题目中说 n−m≤5 ,那么这个式子直接 for 循环枚举就可以了。其中, Cmm+i 和 ti 都可以 O(i) 计算,计算量不超过5次,暴力即可。那么现在问题的关键就是如何快速求出 am+i 了。
其实非常简单,高中数学内容。
我们观察一下
an
的递推式:
我们先不考虑
mod 3389
,易得:
进而易得:
将
ak−1
的表达式带入
ak
的表达式:
继续迭代可得:
带入
i=k
,可得
ak
的通项:
其中,可知 1234k=1234k mod φ(3389) ,可以快速幂计算;而 ∑k−1j=01234j 就是等比数列求和,可以 O(1) 计算。
至此式子就分析完了。
那么 n≤103000 怎么办?还能怎么办,高精度慢慢调呗。。。
—————————————-
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define For(i, j, k) for(int i = j; i <= (int)k; ++ i)
#define Forr(i, j, k) for(int i = j; i >= (int)k; -- i)
#define INF 0x3f3f3f3f
using namespace std;
const ll base = 1e9;//压位,压9位.
const int mo = 3389;
const int maxn = 3000 + 5;
char s[maxn];
struct Big{
int len;
ll a[4005];
inline void init(int x){
memset(a, 0, sizeof(a));
if(x) a[len = 1] = x;
else len = 0;
}
inline void get(){
int l; ll temp;
memset(a, 0, sizeof(a));
scanf("%s", s + 1); l = strlen(s + 1);
Forr(i, l, 1){
if((l - i) % 9 == 0) temp = 1;
a[(l-i)/9+1] += 1ll * (s[i]^48) * temp; temp *= 10;
}
len = (l-1)/9 + 1;
}
inline Big operator + (Big o)const{
Big back; int l;
back.init(0); l = max(len, o.len);
For(i, 1, l){
back.a[i] += a[i] + o.a[i];
back.a[i+1] += back.a[i]/base, back.a[i] %= base;
if(back.a[l+1]) ++ l;
}
back.len = l; return back;
}
inline ll operator - (Big o)const{
ll back = 0;
Forr(i, len, 1)
back = back * base + (a[i]-o.a[i]);
return back;
}
inline Big operator * (Big o)const{
Big back; int l;
back.init(0); l = len + o.len - 1;
For(i, 1, len)
For(j, 1, o.len){
back.a[i+j-1] += a[i] * o.a[j];
back.a[i+j] += back.a[i+j-1]/base, back.a[i+j-1] %= base;
if(back.a[l+1]) ++ l;
}
back.len = l; return back;
}
inline Big operator / (int o)const{
Big back; int l;
back = *this; l = len;
Forr(i, l, 1)
back.a[i-1] += (back.a[i]%o) * base, back.a[i] /= o;
back.a[0] = 0; while(!back.a[l] && l) -- l;
back.len = l; return back;
}
inline ll operator % (int o)const{
ll back = 0;
Forr(i, len, 1)
back = (back * base + a[i]) % o;
return back;
}
inline void print(){
if(!len) puts("0");
else{
while(!a[len]) --len;
printf("%lld",a[len]);
Forr(i, len-1, 1) printf("%09lld", a[i]);
}
}
}n, t, m, C, p, Ans, temp, tmpp;//工业代码高精度.
inline int ksm(int x, int y){
int back = 1;
while(y){
if(y & 1) back = back * x % mo;
x = x * x % mo;
y >>= 1;
}
return back;
}//快速幂.
inline int A(Big x){
return (209 * ksm(1234, x % (mo-1)) % mo + 3181) % mo;
}//求ax的值.
int main(){
int tmp;
n.get(); t.get(); m.get();
tmp = n - m; C.init(1); p.init(1); Ans.init(0); temp.init(1);
for(int i = 0; i <= tmp; ++ i, m = m + temp){
if(i) C = (C * m) / i, p = p * t;
tmpp.init(A(m));
Ans = Ans + C * p * tmpp;//C:组合数;p:t^i次方;tmpp:am的值.
}
Ans.print();
return 0;
}
—————————————-
小结
这题的式子推导难度并不是很大,想到了消去自变量x的影响就基本上解决的这道题。估计本题最大的难度还是在于高精度的调试吧2333.
—————————————-
——wrote by miraclejzd.