hdu 5490 Simple Matrix(数论)

179 篇文章 0 订阅
10 篇文章 0 订阅

题目链接:hdu 5490 Simple Matrix

解题思路

首先将等比和等差数列分开来考虑。

/1234
1a1a1a1a1
2a1+a22a1+a23a1+a24a1+a2
3a1+a2+a33a1+a2+a36a1+2a2+a310a1+3a2+a3

很明显, ai 的系数可以组成一个杨辉三角,并且根据它的性质, ai cn,m 的贡献值为 C(nin+mi1)ai ,n只有10000,枚举i求解即可。

接下来考虑等比数列。其实等比也可以采用计算等差的方式计算,但是m太大,时间上不允许。所以只能换一种做法。
定义

Sij=k=1j(Si1j)

目标为要求出 Snm
当n=1时,有
S1j=S1j1q+S01

A1j=S1j+S01q1 ,并且 A1 为等比数列,公比为q。然后根据 Ai 可以求出 Si+1 Ai+1 。所以枚举i维护首项即可,但是最后我们能很容易得到 Ai ,对应的 Si 则需要减掉相应的偏移量bw,即为构造等比数列而添加的数。

bwi=Si11q1 ,列出每个 bwi Snm 的贡献值。

/1234
1bw1bw1bw1bw1
2bw1+bw22bw1+bw23bw1+bw24bw1+bw2
3bw1+bw2+bw33bw1+bw2+bw36bw1+2bw2+bw310bw1+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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值