20221015_T2B+_推柿子

题意

定义函数 \(F(x)=\prod\limits_{i=0}^x \binom{x}{i}\)\(G(x)\)\(F(x)\) 的因数和,求 \(\sum\limits_{i=1}^N G(i)\)

题解

赛时得分 50/100 (想到了类似正解,当时没有想着筛素数,能卡到 80 pts)

首先,我们可以想到因数和的计算公式。假如说 \(F(x)=p_1^{k_1}p_2^{k_2}p_3^{k_3}...p_n^{k_n}\)\(G(x)=\Big(\sum_{i=0}^{k_1}p_1^{i} \Big)\Big(\sum_{i=0}^{k_2}p_2^i \Big)...\Big(\sum_{i=0}^{k_n}p_n^i \Big)\)

这样的话我们可以选择把 \(F(x)\) 的因数情况分解出来。

经过一阵简单的推柿子,我们能知道 \(F(x)=\frac{(n!)^{n+1}}{(\prod_{i=1}^ni!)^2}\),然后我们只需要考虑素数上的指数就好了。

我原来的方法是因为要每个 \(G\) 都求,所以就直接枚举 \(G\) 里的 \(i\),然后枚举倍数等等,复杂度也是 \(\mathcal{O}(n^2)\) 的,只不过常数非常大。

但是有一种常数很小的办法,不去枚举 \(i\) 因为指数是具有前缀性质的。所以直接枚举素数 \(p\),然后后面记录指数的修改情况。

代码

被注释的是那种常数很大方法,只能获得 \(80\) 分,不想卡常了。

#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void read(T &x) {
	x = 0; register char ch = getchar();
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
}
template<typename T, typename ...Args> inline void read(T &x, Args &...args) {read(x); read(args...);}

const int N = 2e5 + 10, qwq = 2e7 + 10;
typedef long long ll;
int n, P; 

int prime[N], cnt0;
bool notprime[N];
void intt(int T) {
    notprime[1] = 1;
    for(int i = 2; i <= T; ++i) {
        if(!notprime[i]) prime[++cnt0] = i;
        for(int j = 1; j <= cnt0; ++j) {
            int t = prime[j] * i;
            if(t > T) break;
            notprime[t] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}

inline ll qpow(ll x, int y) {
	ll res = 1;
	while(y) {
		if(y & 1) res = 1ll * res * x % P;
		x = 1ll * x * x % P;
		y >>= 1;
	}
	return res;
}
ll cnt[N], ans[N];
inline int calc(int x, int y) { // log
    int res = 0;
    while(x % y == 0) res++, x /= y;
    return res;
}
int power[qwq], pre[qwq], tot;
int Calc(int p, int c) {
    while(tot < c) {
        ++tot; power[tot] = 1ll * power[tot - 1] * p % P;
        pre[tot] = (pre[tot - 1] + power[tot]);
        if(pre[tot] >= P) pre[tot] -= P;
    }
    return pre[c];
}

signed main() {
    freopen("gonna.in", "r", stdin);
    freopen("gonna.out", "w", stdout);
	read(n, P);
    intt(20000);
	// for(int i = 1; i <= n; ++i) {
    //     ll res = 1;
    //     for(int j = 2; j <= i; ++j) cnt[j] = 2 * j - i - 1; 
    //     for(register int k = 1; prime[k] <= i; ++k) {
    //         int y = prime[k]; 
    //         for(register int j = y * 2; j <= i; j += y) cnt[y] += calc(j, y, k) * cnt[j]; // O(n)
    //         res = 1ll * res * (qpow(y, cnt[y] + 1) - 1) % P * qpow(y - 1, P - 2) % P;
    //     }
    //     ans = (ans + res) % P;
    // }
    ll now = 0, sum = 0;
    for(int i = 1; i <= n; ++i) ans[i] = 1;
    for(int i = 1; prime[i] <= n && i <= cnt0; ++i) {
        int p = prime[i]; now = sum = 0;
        tot = 0; power[0] = pre[0] = 1;
        for(int j = 1; j <= n; ++j) {
            now += calc(j, p); sum += now;
            int pd = Calc(p, now * (j + 1) - 2 * sum);
            ans[j] = 1ll * ans[j] * pd % P;
        }
    }
    ll tans = 0;
    for(int i = 1; i <= n; ++i) tans += ans[i], tans %= P;
    cout << tans << endl;
	return 0;
}

posted @ 2022-11-09 15:17  Mercury_City  阅读(20)  评论(0编辑  收藏  举报