CSP-S 模拟 轻飘飘的时间 (莫比乌斯反演)(杜教筛)(Lucas)

题意:给定 n , m , d n,m,d n,m,d,求
∑ i = 1 n ∑ j = 1 m ( g c d ( i , j ) B ) \sum_{i=1}^n\sum_{j=1}^m\binom{gcd(i,j)}{B} i=1nj=1m(Bgcd(i,j))
直接反演
∑ d = 1 n ( d B ) ∑ l = 1 n d μ ( l ) ⌊ n d l ⌋ ⌊ m d l ⌋ \sum_{d=1}^n\binom{d}{B}\sum_{l=1}^{\frac{n}{d}}\mu (l)\left \lfloor \frac{n}{dl} \right \rfloor\left \lfloor \frac{m}{dl} \right \rfloor d=1n(Bd)l=1dnμ(l)dlndlm
化到这步的时候我想的是
对前面整除分块,组合数列求和,内层套一个整除分块,内层套的时候用杜教筛 μ \mu μ 的前缀和
算了一下复杂度,发现是 ∑ i = 1 n n i = n 3 / 4 \sum_{i=1}^{\sqrt n}\sqrt \frac{n}{i}=n^{3/4} i=1n in =n3/4,加上杜教筛的 O ( n 2 / 3 ) O(n^{2/3}) O(n2/3),亲测大样例 10 s 10s 10s
我们按照套路对上式继续化简,枚举 d l dl dl
∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ l ∣ T μ ( l ) ( T / l B ) \sum_{T=1}^n\left \lfloor \frac{n}{T} \right \rfloor\left \lfloor \frac{m}{T} \right \rfloor\sum_{l|T}\mu (l)\binom{T/l}{B} T=1nTnTmlTμ(l)(BT/l)
考虑直接筛后面一坨的前缀和就可以整除分块
f ( T ) = ∑ l ∣ T μ ( l ) ( T / l B ) f(T)=\sum_{l|T}\mu (l)\binom{T/l}{B} f(T)=lTμ(l)(BT/l)
S ( n ) = ∑ i = 1 n f ( n ) S(n)=\sum_{i=1}^nf(n) S(n)=i=1nf(n)
考虑到有 μ \mu μ,卷上一个 I I I
那么就有
I ∗ S ( n ) = ∑ i = 1 n ∑ l ∣ i ( i / l B ) [ l = 1 ] = ∑ i = 1 n ( i B ) = ( n + 1 B + 1 ) I*S(n)=\sum_{i=1}^n\sum_{l|i}\binom{i/l}{B}[l=1]=\sum_{i=1}^n\binom{i}{B}=\binom{n+1}{B+1} IS(n)=i=1nli(Bi/l)[l=1]=i=1n(Bi)=(B+1n+1)
所以
I ∗ S ( n ) = S ( n ) + ∑ i = 2 n S ( ⌊ n i ⌋ ) = ( n + 1 B + 1 ) I*S(n)=S(n)+\sum_{i=2}^nS(\left \lfloor \frac{n}{i} \right \rfloor)=\binom{n+1}{B+1} IS(n)=S(n)+i=2nS(in)=(B+1n+1)
杜教筛即可,预处理往大的预处理,由于带 l o g log log,到 3 e 6 3e6 3e6 就已经差不多了
复杂度是整除分块的 O ( n ) O(\sqrt n) O(n ) 和杜教筛的 O ( n 2 / 3 ) O(n^{2/3}) O(n2/3)
然后组合数还要用一下 l u c a s lucas lucas

#include<bits/stdc++.h>
#define cs const
#include<tr1/unordered_map>
using namespace std;
using namespace tr1;
typedef long long ll;
ll read(){
	ll cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
cs int Mod = 9990017;
ll n, m, B;
int fac[Mod + 5], ifac[Mod + 5];
ll add(ll a, ll b){ return (a + b) >= Mod ? (a + b) % Mod : a + b; }
ll mul(ll a, ll b){ if(a >= Mod) a %= Mod; if(b >= Mod) b %= Mod; ll r = a * b; if(r >= Mod) r %= Mod; return r; }
ll ksm(ll a, ll b){ ll ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans; }
ll C(ll n, ll m){ 
	if(n < 0 || m < 0 || n < m) return 0;
	return mul(fac[n], mul(ifac[m], ifac[n-m]));
}
ll Lucas(ll n, ll m){ 
	if(n < Mod && m < Mod) return C(n, m);
	return mul(Lucas(n / Mod, m / Mod), C(n % Mod, m % Mod));
}
cs int K = 5e6;
int prim[K + 5]; bool isp[K + 5]; 
int tot, mu[K + 5], f[K + 5], g[K + 5];
ll calc(ll x){ return Lucas(x + 1, B + 1); }
unordered_map<ll, int> MP;
ll F(ll x){
	if(x <= K) return f[x];
	if(MP.count(x)) return MP[x];
	ll ans = Lucas(x + 1, B + 1); 
	for(ll l = 2, r; l <= x; l = r + 1){
		ll v = x / l; r = x / v;
		ans = add(ans, Mod - mul(r-l+1, F(v)));
	} return MP[x] = ans;
}
void prework(){
	fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
	for(int i = 2; i < Mod; i++) fac[i] = mul(fac[i-1], i);
	ifac[Mod-1] = ksm(fac[Mod-1], Mod-2);
	for(int i = Mod-2; i >= 2; i--) ifac[i] = mul(ifac[i+1], i+1);
	mu[1] = 1;
	for(int i = 2; i <= K; i++){
		if(!isp[i]) prim[++tot] = i, mu[i] = -1;
		for(int j = 1; j <= tot; j++){
			if(i * prim[j] > K) break;
			isp[i * prim[j]] = 1;
			if(i % prim[j] == 0) break;
			mu[i * prim[j]] = mu[i] * mu[prim[j]];
		}
	}
	for(int i = 1; i <= K; i++) g[i] = C(i, B);
	for(int i = 1; i <= K; i++){
		for(int j = i; j <= K; j += i){
			f[j] = add(f[j], mul(mu[i], g[j / i]));
		}
	}
	for(int i = 1; i <= K; i++) f[i] = add(f[i-1], f[i]);
}
int main(){
	n = read(), m = read(), B = read();
	if(n > m) swap(n, m);
	prework();
	ll ans = 0, las = 0;
	for(ll l = 1, r; l <= n; l = r + 1){
		ll v1 = n / l, v2 = m / l; r = min(n / v1, m / v2);
		ll nx = F(r);
		ans = add(ans, mul(add(nx, Mod - las), mul(v1, v2)));
		las = nx;
	} cout << ans; return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值