BZOJ 2005 [Noi2010]能量采集(严格来说应该叫欧拉反演)

86 篇文章 0 订阅
2 篇文章 0 订阅

练习一发LaTeX
a n s = ∑ x = 1 n ∑ y = 1 m 2 g c d ( x , y ) − 1 = ∑ x = 1 n ∑ y = 1 m ( − 1 + 2 ∑ p ∣ g c d ( x , y ) φ ( p ) ) = 2 ∑ x = 1 n ∑ y = 1 m ∑ p ∣ g c d ( x , y ) φ ( p ) − n ∗ m = 2 ∑ p = 1 m i n ( n , m ) φ ( p ) ∑ x = 1 n ∑ y = 1 m [ p ∣ x ] [ p ∣ y ] − n ∗ m = 2 ∑ p = 1 m i n ( n , m ) φ ( p ) ⌊ n p ⌋ ⌊ m p ⌋ − n ∗ m \begin{aligned}ans &= \sum_{x=1}^n\sum_{y=1}^m2gcd(x,y)-1\\ &=\sum_{x=1}^n\sum_{y=1}^m\left(-1+2\sum_{p|gcd(x,y)}\varphi(p)\right)\\ &=2\sum_{x=1}^n\sum_{y=1}^m\sum_{p|gcd(x,y)}\varphi(p) - n*m\\ &=2\sum_{p=1}^{min(n,m)}\varphi(p)\sum_{x=1}^n\sum_{y=1}^m[p|x][p|y] - n*m\\ &=2\sum_{p=1}^{min(n,m)}\varphi(p)\lfloor\frac np\rfloor \lfloor\frac mp\rfloor - n*m\end{aligned} ans=x=1ny=1m2gcd(x,y)1=x=1ny=1m1+2pgcd(x,y)φ(p)=2x=1ny=1mpgcd(x,y)φ(p)nm=2p=1min(n,m)φ(p)x=1ny=1m[px][py]nm=2p=1min(n,m)φ(p)pnpmnm
这个搁今天得整除分块后杜教筛1e10+多组数据

AC Code:

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
using namespace std;

int n,m,phi[maxn],pr[maxn/8],cnt_pr;
bool vis[maxn];

int main()
{
	scanf("%d%d",&n,&m); if(n>m) swap(n,m);
	phi[1] = 1;
	LL ans = 1ll*n*m;
	for(int i=2;i<=n;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , phi[i]=i-1;
		for(int j=0;pr[j]*i<=n;j++)
		{
			vis[pr[j] * i] = 1;
			if(i % pr[j] == 0){ phi[i*pr[j]]=phi[i]*pr[j];break; }
			phi[i*pr[j]] = phi[i] * phi[pr[j]];
		}
		ans += 1ll*(2*phi[i])*(n/i)*(m/i);
	}
	printf("%lld\n",ans);
}

upd:自己杠精了。
∑ i = 1 n ∑ j = 1 n j φ ( i ) = ∑ j = 1 n ∑ i = 1 n j φ ( i ) = ∑ j = 1 n Φ ( n j ) = ∑ i = 1 n i = n ( n + 1 ) 2 \begin{aligned} \sum_{i=1}^n\sum_{j=1}^{\frac nj} \varphi(i) = \sum_{j=1}^n\sum_{i=1}^{\frac nj} \varphi(i) = \sum_{j=1}^n \Phi(\frac nj) = \sum_{i=1}^n i = \frac {n(n+1)}2 \end{aligned} i=1nj=1jnφ(i)=j=1ni=1jnφ(i)=j=1nΦ(jn)=i=1ni=2n(n+1)
AC Code:

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
using namespace std;

int n,m,phi[maxn],pr[maxn/8],cnt_pr;
bool vis[maxn];
map<int,LL>mp;

LL solve(int now)
{
	if(now <= 2137) return phi[now];
	if(mp.count(now)) return mp[now];
	LL &ret=mp[now]=1ll*now*(now+1)/2;
	for(int i=2,nxt;i<=now;i=nxt+1)
	{
		int tmp = now/i;
		nxt = now / tmp;
		ret -= solve(tmp) * (nxt-i+1);
	}
	return ret;
}

int main()
{
	scanf("%d%d",&n,&m); if(n>m) swap(n,m);
	phi[1] = 1;
	LL ans = -1ll*n*m;
	for(int i=2;i<=min(n,2137);i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , phi[i]=i-1;
		for(int j=0;pr[j]*i<=n;j++)
		{
			vis[pr[j] * i] = 1;
			if(i % pr[j] == 0){ phi[i*pr[j]]=phi[i]*pr[j];break; }
			phi[i*pr[j]] = phi[i] * (pr[j]-1);
		}
		phi[i] += phi[i-1];
	}
	for(int i=1,nxt,psolve=0,tmp,div1,div2;i<=n;i=nxt+1)
	{
		div1 = n / i , div2 = m / i;
		nxt = min(n/div1,m/div2);
		ans += 2ll * ((tmp=solve(nxt))-psolve) * div1 * div2;
		psolve = tmp;
	}
	printf("%lld\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值