其他分享
首页 > 其他分享> > P1447 [NOI2010] 能量采集(莫比乌斯反演)

P1447 [NOI2010] 能量采集(莫比乌斯反演)

作者:互联网

题目传送门

题意:在一个 n ∗ m n*m n∗m的矩阵上,将每个点和点 ( 0 , 0 ) (0,0) (0,0)连起来,假设线段上除了两端点有 k k k个点,这个点的贡献是 2 ∗ k + 1 2*k+1 2∗k+1,求这 n ∗ m n*m n∗m个点的贡献和。

思路:可以知道,假设有点 ( i , j ) (i,j) (i,j), ( i , j ) (i,j) (i,j)的贡献是 2 ∗ g c d ( i , j ) − 1 2*gcd(i,j)-1 2∗gcd(i,j)−1。那么答案显而易见:
a n s = ∑ i = 1 n ∑ j = 1 m ( 2 ∗ g c d ( i , j ) − 1 ) = 2 ∗ ∑ i = 1 n ∑ j = 1 m ( g c d ( i , j ) ) − n ∗ m = 2 ∗ ∑ g = 1 m i n ( n , m ) g ∗ ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = g ] − n ∗ m \begin{aligned}\\ ans&=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}(2*gcd(i,j)-1)\\ &=2*\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}(gcd(i,j))-n*m\\ &=2*\sum\limits_{g=1}^{min(n,m)}g*\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[gcd(i,j)=g]-n*m \end{aligned} ans​=i=1∑n​j=1∑m​(2∗gcd(i,j)−1)=2∗i=1∑n​j=1∑m​(gcd(i,j))−n∗m=2∗g=1∑min(n,m)​g∗i=1∑n​j=1∑m​[gcd(i,j)=g]−n∗m​

然后上面这个式子就可以 O ( n n ) O(n\sqrt n) O(nn ​)求了。

C o d e Code Code

// Author : ACfunhsl
// Time : 2021/5/17 14:13:11
#define int long long
const int N = 1e5+50;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
bool ok[N];
int p[N],cnt=0,mu[N];
void euler()
{
	mu[1] = 1;
	for(int i=2;i<N;i++)
	{
		if(!ok[i])
		{
			p[++cnt] = i;
			mu[i] = -1;	
		}
		for(int j=1;j<=cnt&&i*p[j]<N;j++)
		{
			ok[i*p[j]] = 1;
			if(i%p[j]==0)
			{
				mu[i*p[j]] = 0;
				break;
			}
			else mu[i*p[j]] = -mu[i];
		}
	}
	for(int i=1;i<N;i++)
		mu[i] += mu[i-1];
}
int k;
int cal(int n,int m)
{
	n/=k;m/=k;
	int mi = min(n,m),res = 0;
	for(int l=1,r;l<=mi;l=r+1)
	{
		r = min(n/(n/l),(m/(m/l)));
		res += (n/l)*(m/l)*(mu[r] - mu[l-1]);
	}
	return res;
}
signed main()
{
	euler();
	int n,m;
	cin>>n>>m;
	int res = 0;
	for(int i=1;i<=min(n,m);i++)
	{
		k = i;
		res += cal(n,m) * k;
	}
	res = res * 2 - n*m;
	cout<<res<<endl;
	return 0;
}

标签:P1447,gcd,limits,int,res,sum,mu,反演,NOI2010
来源: https://blog.csdn.net/Joker_He/article/details/116943541