题目链接:bzoj3933 & CQOI2015多项式.
—————————————-
题目大意如下。
已知整数 n,t 以及数列 ak ,求数列 bk 的表达式使得下式恒成立:
其中,数列 ak 的递推式为:
告诉你整数 m ,输出 bm 的值。( 1≤n≤103000, 0≤t≤10000, 0≤n−m≤5 )
—————————————-
我们观察这个式子:
假如这个式子恒成立,那么就说明 bk 的取值与自变量 x 无关,而只跟已知量 ak、t 有关。
所以我们先考虑把已知数都放到等式的同一边,也就是将 x 带入 x+t ,有:
对于左边的 (x+t)k ,我们用二项式定理展开:
然后利用恒等变换考虑先枚举 x 的贡献:
至此,我们得到了:
这时我们发现:等式两边自变量 x 的影响都是一样的,假如我们强制令 bk=∑ni=kCkiaiti−k ,那么两边的 xk 便可以消去了,所以有:
进一步变形:
由于题目中说 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
#include
#include
#include
#include
#include
#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.