解题思路
首先将等比和等差数列分开来考虑。
/ | 1 | 2 | 3 | 4 |
---|---|---|---|---|
1 | a1 | a1 | a1 | a1 |
2 | a1+a2 | 2a1+a2 | 3a1+a2 | 4a1+a2 |
3 | a1+a2+a3 | 3a1+a2+a3 | 6a1+2a2+a3 | 10a1+3a2+a3 |
很明显, ai 的系数可以组成一个杨辉三角,并且根据它的性质, ai 为 cn,m 的贡献值为 C(n−in+m−i−1)∗ai ,n只有10000,枚举i求解即可。
接下来考虑等比数列。其实等比也可以采用计算等差的方式计算,但是m太大,时间上不允许。所以只能换一种做法。
定义
Sij=∑k=1j(Si−1j)
目标为要求出 Snm
当n=1时,有
S1j=S1j−1∗q+S01
令 A1j=S1j+S01q−1 ,并且 A1 为等比数列,公比为q。然后根据 Ai 可以求出 Si+1 和 Ai+1 。所以枚举i维护首项即可,但是最后我们能很容易得到 Ai ,对应的 Si 则需要减掉相应的偏移量bw,即为构造等比数列而添加的数。
令 bwi=Si−11q−1 ,列出每个 bwi 对 Snm 的贡献值。
/ | 1 | 2 | 3 | 4 |
---|---|---|---|---|
1 | bw1 | bw1 | bw1 | bw1 |
2 | bw1+bw2 | 2bw1+bw2 | 3bw1+bw2 | 4bw1+bw2 |
3 | bw1+bw2+bw3 | 3bw1+bw2+bw3 | 6bw1+2bw2+bw3 | 10bw1+3bw2+bw3 |
我们发现和等差的系数是一样的,所以对应减掉即可。
对于组合数,因为m很大,但是n只有10000,所以单次组合数是可求的,在枚举i的过程中,组合数可以递推,这样保证时间复杂度为 o(n)
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 2 * 1e4;
int fac[maxn + 5], inv[maxn + 5];
int pow_mod(ll x, int n) {
ll ret = 1;
while (n) {
if (n&1) ret = ret * x % mod;
x = x * x % mod;
n >>= 1;
}
return ret;
}
int C(int k, int n) {
if (k > n) return 0;
k = min(k, n-k);
int ret = 1;
for (int i = 0; i < k; i++)
ret = 1LL * ret * (n-i) % mod * inv[(i+1)] % mod;
return ret;
}
int main () {
inv[0] = 1;
for (int i = 1; i <= maxn; i++) inv[i] = pow_mod(i, mod-2);
int cas;
scanf("%d", &cas);
for (int kcas = 1; kcas <= cas; kcas++) {
int b, q, a, d, n, m, ans = 0;
scanf("%d%d%d%d%d%d", &b, &q, &a, &d, &n, &m);
a %= mod, b %= mod, d %= mod, q %= mod;
int cnt = C(n-1, n+m-2);
int bw = 0, b1 = b, del = 0, invq = pow_mod(q-1, mod-2);
for (int i = 1; i <= n; i++) {
// 等差
ans = (ans + 1LL * cnt * a % mod) % mod;
a = (a + d) % mod;
// 等比
bw = 1LL * b1 * invq % mod;
b1 = (b1 + bw) % mod;
ans = (ans - 1LL * cnt * bw % mod + mod) % mod;
// 组合数
cnt = 1LL * cnt * (n-i) % mod * pow_mod(n+m-1-i, mod-2) % mod;
}
ans = (ans + 1LL * b1 * pow_mod(q, m-1) % mod) % mod;
printf("Case #%d: %d\n", kcas, ans);
}
return 0;
}