51nod 1769 Clarke and math2

本文探讨了一种涉及数论和组合数学的问题解决方案,通过定义一个特定的数学模型,利用积性函数、Lucas定理等技巧求解复杂组合序列问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:

他突然想算这么一个式子,给出 f(i),1≤i≤n ,要求算
g(i)=∑i1∣i∑i2∣i1∑i3∣i2⋯∑ik∣ik−1f(ik) mod 1000000007 (1≤i≤n,ij∈N+)

题解:

设c(i)为i经过k轮变换后为1的方案数。
那么显然可以这样求g(i*j) += f(i) * c(j) (1 <= j <= n/i).
由c(i)的性质很容易想到它是一个积性函数,那么我们就可以线筛它了。
i=pqkk
c(i)=c(pqkk)

所以现在要求c(pq)
我们可以用挡板问题的思想来快速求c(pq)
等价于有q+1个球,有一个必须单独放一个箱子里,其余的放进k-1个箱子,每个箱子不一定要放球。
c(pq)=Cqq+k+1

k辣么大,怎么办?
Lucas定理:
=Cn mod pm mod pCn/pm/p(mod p)

此题当中套公式可得:
c(pq)=Cq(q+k+1) mod p

于是此题解决。

Code:

#include<cstdio>
#include<cstring>
#define ll long long
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
using namespace std;

const ll mo = 1e9 + 7;

const ll Maxn = 500005;
char ch[1000005];
ll fac[35], nf[35];
bool bz[Maxn]; ll p[Maxn], c[Maxn], d[Maxn], z[Maxn];
ll n, m, f[Maxn], s[Maxn];

ll ksm(ll x, ll y) {
    ll s = 1;
    while(y) {
        if(y & 1) s = (s * x) % mo;
        x = (x * x) % mo; y /= 2;
    }
    return s;
}

ll C(ll n, ll m) {
    ll s = 1;
    fo(i, n - m + 1, n) s = (s * i) % mo;
    return s * nf[m] % mo;
}

int main() {
    fac[0] = 1; fo(i, 1, 30) fac[i] = (fac[i - 1] * i) % mo;
    fo(i, 0, 30) nf[i] = ksm(fac[i], mo - 2);
    scanf("%lld", &n);
    scanf("%s", ch + 1);
    ll lc = strlen(ch + 1);
    ll yu = 0;
    fo(i, 1, lc) {
        yu = yu * 10 + ch[i] - 48;
        yu %= mo;
    }
    fo(i, 1, n) scanf("%lld", &f[i]);
    c[1] = 1;
    fo(i, 2, n) {
        if(!bz[i]) p[++ p[0]] = i, c[i] = C(yu, 1), d[i] = i, z[i] = 1;
        fo(j, 1, p[0]) {
            ll k = i * p[j];
            if(k > n) break;
            bz[k] = 1;
            if(i % p[j] == 0) {
                z[k] = z[i] + 1;
                d[k] = d[i] * p[j];
                c[k] = c[k / d[k]] * C(yu + z[k] - 1, z[k]) % mo;
                break;
            }
            z[k] = 1;
            d[k] = p[j];
            c[k] = c[i] * c[p[j]] % mo;
        }
    }
    fo(i, 1, n) fo(j, 1, n / i) s[i * j] = (s[i * j] + f[i] * c[j]) % mo;
    fo(i, 1, n) printf("%lld ", s[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值