bzoj3944(杜教筛)

Description
给定一个正整数 N ( N &lt; = 2 31 − 1 ) N(N&lt;=2^{31}-1) N(N<=2311)
a n s 1 = ∑ i = 1 N ϕ ( i ) , a n s 2 = ∑ i = 1 N μ ( i ) ans1=\sum_{i=1}^N\phi(i),ans2=\sum_{i=1}^N\mu(i) ans1=i=1Nϕ(i),ans2=i=1Nμ(i),多组询问
Input
一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个非负整数N,代表一组询问
Output
一共T行,每行两个用空格分隔的数ans1,ans2
Sample Input
6
1
2
8
13
30
2333
Sample Output
1 1
2 0
22 -2
58 -3
278 -3
1655470 2


杜教筛模板题
入门见:https://blog.csdn.net/a1035719430/article/details/85208451
关于狄利克雷卷积:https://blog.csdn.net/a1035719430/article/details/84958962
由上面这个博文我们可以知道
μ ∗ I = e , ϕ ∗ I = ε \mu*I=e,\phi*I=\varepsilon μI=e,ϕI=ε
e e e的前缀和就是 1 1 1, ε \varepsilon ε的前缀和是 n ∗ ( n + 1 ) 2 \frac{n*(n+1)}{2} 2n(n+1)

然后直接做杜教筛就行了
注意这题的坑点, n + 1 n+1 n+1正好爆了 i n t int int

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x],y = e[i].y;i;i = e[i].n,y = e[i].y)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define fr first
#define se second
int rd()
{
	int num = 0;char c = getchar();bool flag = true;
	while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
	while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
	if(flag) return num;else return -num;
}
const int N = 2e6;
unordered_map<int,ll>Phi,Miu;
int prime[N+10],v[N+10];
ll phi[N+10],miu[N+10];
inline ll get(int i,int j)
{
	return 1ll*(i+j)*(j-i+1)/2;
}
int cas = 0;
Pll solve(int n)
{
	if(n<=N) return mp(phi[n],miu[n]);
	if(Miu.find(n) != Miu.end()) return mp(Phi[n],Miu[n]);
	Pll now = mp(1ll*n*(1ll*n+1)/2,1);int i = 2;
	while(i <= n)
 	{
		int j = n/(n/i);
		Pll to = solve(n/i);
		now.fr -= 1ll*(j-i+1)*to.fr; now.se -= 1ll*(j-i+1)*to.se;
		if(j == n) break;
		i = j+1;
	}
	Phi[n] = now.fr; Miu[n] = now.se;
	return mp(Phi[n],Miu[n]);
}
void pre()
{
	miu[1] = 1;phi[1] = 1;
	rep(i,2,N)
	{
		if(!phi[i]) prime[++prime[0]] = i,phi[i] = i-1,v[i] = i,miu[i] = -1;
		rep(j,1,prime[0])
		{
			if(i*prime[j]>N || v[i] < prime[j]) break;
			v[i*prime[j]] = prime[j];
			phi[i*prime[j]] = phi[i] * (i%prime[j]?prime[j]-1:prime[j]);
			if(i%prime[j] == 0) break;
			miu[i*prime[j]] = -miu[i];
		} 
	}
	rep(i,2,N) miu[i] += miu[i-1],phi[i] += phi[i-1];
}
int main()
{
	pre();
	int T = rd();
	while(T--)
	{
		int x = rd(); 
		Pll now = solve(x);
		printf("%lld %lld\n",now.fr,now.se);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值