这个看了秦总博客学会的,附上地址
博客介绍得很详细。
我原来的思路,找到每一个ai,bi对(n,m)的贡献。
我们可以写出
c(n,m)=∑ni=1ai∗(n+m−1−im−1)+∑mi=1bi∗(n+m−1−in−1)
ai=a1+(i−1)d
bi=b1∗qi−1
等差数列很容易求出来,但是等比数列很难,比赛的时候一直考虑等比数列能不能像等差数列一项求出通项,事实上失败了,并不知道有没有什么高级的方法能搞出来。
事实上,等差数列求和,一共就n项,这个时候我们暴力累加都可以完成任务,于是我们主要工作放到了等比数列上面。如果我们对初等数学还敏感的话,我们会想到能不能构造出一个等比或者等差数列?(我现在的数学水平真是不忍直视)
那么我们先把所有ai变成0,单独看bi。
对于第0行
0
我们研究第1行的第i个数:
c(1,i)=∑ik=1bk
我们可以推出:
c(1,i)=q∗c(1,i−1)+b1
即:
c(1,i)=q∗c(1,i−1)+c(0,1)
这个形式直接就化成了
c(1,i)+c(0,1)q−1=q∗(c(1,i−1)+c(0,1)q−1)
这样我们就构造出了一个等比数列,我们需要做的事情就是把
c(1,0)=c(0,1)q−1
我们只需要把
ai−c(0,1)q−1
就可以了。
这样我们把第一行变成了一个等比数列,那么第二行也可以用同样的方法变成等比数列。以此类推,第n行也可以变成等比数列。
我们这是时候需要找到每行的
c(i,0)
的值。
我们写几项就会发现:
c(i,0)=qi−1(q−1)i∗b1
那么我们要求的东西就会变成:
c(n,m)=∑ni=1(ai∗(n+m−1−im−1)−qi−1(q−1)i∗b1)+qn−1q−1n∗b1∗qm
这样,后面一项用快速幂即可完成,前面一项只需要累加就可以了,注意处理逆元。注意
(n+m−1−(i+1)m−1)=(n+m−1−im−1)∗n−in+m−1−i
,其实,这个倒过来求比较好,因为
(m−1m−1)=1
是个定值,所以我们可以倒过来求,比较方便。
下面附上AC代码:
#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define MAXN 10010
#define MOD 1000000007
using namespace std;
void ex_gcd(LL a,LL b,LL&d ,LL& x,LL& y){
if(!b) {d = a;x = 1;y = 0;}
else{ex_gcd(b,a%b,d,y,x);y -= x*(a/b);}
}
LL inv(LL a,LL mod){
LL d,x,y;
ex_gcd(a,mod,d,x,y);
return d == 1 ? (x+mod)%mod : -1;
}
LL quickpow(LL a,LL p){
LL ans=1;
while(p){
if(p&1) ans = (ans*a)%MOD;
a = (a*a)%MOD;
p >>= 1;
}
return ans;
}
LL b1,q,a1,d;
int n,m;
LL A(){
b1 %= MOD; q %= MOD; a1 %= MOD; d %= MOD;
LL res1 = (a1+d*(n-1))%MOD;
LL inv1 = inv(q-1,MOD);
LL tem = (inv1*q)%MOD;
LL res2 = (((quickpow(tem,n-1)*inv1)%MOD)*b1)%MOD;
LL res3 = 1;
LL ans = (res1+MOD-res2)%MOD;
inv1 = inv(q,MOD);
tem = (q-1)*inv1%MOD;
FOR(i,1,n){
res1 = (res1+MOD-d)%MOD;
res2 = res2*tem%MOD;
LL t = (LL)(m-1)+(LL)i;
LL tt = inv((LL)i,MOD);
res3 = (res3*t%MOD)*tt%MOD;
ans += ((res1+MOD-res2)%MOD)*res3%MOD;
}
return ans;
}
LL B(){
LL p = (LL)m+n-1;
LL t1 = quickpow(q,p);
LL t2 = quickpow(q-1,n);
t2 = inv(t2,MOD);
LL ans = (t1*t2%MOD)*b1%MOD;
return ans;
}
int main()
{
//freopen("test.in","r",stdin);
int T,tCase = 0;
scanf("%d",&T);
while(T--){
printf("Case #%d: ",++tCase);
scanf("%I64d%I64d%I64d%I64d%d%d",&b1,&q,&a1,&d,&n,&m);
LL t1 = A();
LL t2 = B();
LL ans = (t1+t2)%MOD;
printf("%I64d\n",ans);
}
return 0;
}