AtCoder Beginner Contest 206 E - Divide Both(容斥)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 206 E - Divide Both(容斥)相关的知识,希望对你有一定的参考价值。

LINK

不是多么难的一题,但是却写了很久,下次不能再脑溢血了…


题意

x ∈ [ L , R ] & & y ∈ [ L , R ] x\\in[L,R]\\&\\&y\\in[L,R] x[L,R]&&y[L,R]的合法 ( x , y ) (x,y) (x,y)对的数量

其中设 g c d ( x , y ) = k gcd(x,y)=k gcd(x,y)=k,满足 k ! = 1 & & k ! = x & & k ! = y k!=1\\&\\&k!=x\\&\\&k!=y k!=1&&k!=x&&k!=y


考虑到 L , R L,R L,R范围不大,枚举每个值单独进行计算

枚举 x x x,我们考虑计算 ( x , y ) & & y > x (x,y)\\&\\&y>x (x,y)&&y>x的方案有多少

让我们先不管是否满足要求,先求出 [ x + 1 , R ] [x+1,R] [x+1,R]中与 x x x不互质的数有多少

这个我们可以对 x x x分解质因子,只要包含任意一个 x x x的质因子就不互质

所以我们加上包含有一个质因子的,减去有两个质因子的,加上有三个质因子的…

但是这么算还是重复,因为自己不能作为 g c d gcd gcd

所以我们再减去 R / x − 1 R/x-1 R/x1即可

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7;
const int maxn = 1e6+10;
int L,R,vis[maxn],prime[maxn],mi[maxn],top;
vector<int>vec;
void init()
{
	for(int i=2;i<=1000000;i++)
	{
		if( !vis[i] )	prime[++top] = i, mi[i] = i;
		for(int j=1;j<=top&&prime[j]*i<=1000000;j++)
		{
			vis[prime[j]*i] = 1;	mi[prime[j]*i] = prime[j];
			if( i%prime[j]==0 )	break;
		}
	}
}
int get(int x,int L,int R)
{
	while( x!=1 )
	{
		vec.push_back( mi[x] );
		int k = mi[x];
		while( x!=1 && mi[x]==k )	x /= mi[x];
	}
	int w = vec.size(), ans = 0;//先找和自己不互质的数 
	for(int i=1;i<(1<<w);i++)
	{
		int r = 1, bit = 0;
		for(int j=0;j<w;j++)
			if( (i>>j)&1 )	r *= vec[j], bit++;
		if( bit&1 )	ans += R/r-(L-1)/r;
		else	 ans -= R/r-(L-1)/r;
	}
	vec.clear();
	return ans;	
}
signed main()
{
	init();
	cin >> L >> R;
	L = max( L,2ll ), R = max( R,L );
	long long ans = 0;
	for(int i=L;i<=R;i++)	ans += get(i,i+1,R);
	for(int i=L;i<=R;i++)	ans -= (R/i-1);
	cout << ans*2;
}

也有另外一种做法

我们直接枚举 x x x作为 g c d gcd gcd,其中 x x x不应该含有两个相同的质因子,否则会算重复

显然有 k = R / x − ( L − 1 ) / x k=R/x-(L-1)/x k=R/x(L1)/x个数包含因子 x x x

那么答案是加上 k ∗ ( k − 1 ) / 2 k*(k-1)/2 k(k1)/2吗?

然而,这 k ∗ ( k − 1 ) / 2 k*(k-1)/2 k(k1)/2的数对确实有公因子 x x x,但可能他们的 g c d gcd gcd f x fx fx,其中 f f f未知

所以我们采用容斥的做法,若 x x x有奇数个质因子,加上答案,否则减去答案.

其实和上面的道理差不多。

贴一个官方题解的代码

#include<bits/stdc++.h>
 
using namespace std;
 
int main(){
  long long l,r;
  cin >> l >> r;
  long long res=0;
  vector<int> cnt(1048576,0);
  for(long long i=2;i<=r;i++){
    if(cnt[i]!=0){continue;}
    for(long long j=i;j<=r;j+=i){cnt[j]++;}
    for(long long j=i*i;j<=r;j+=i*i){cnt[j]=-1000000007;}
  }
  for(long long i=2;i<=r;i++){
    if(cnt[i]<0){continue;}
    long long cc=(r/i)-((l-1)/i);
    if(cnt[i]%2){res+=(cc*(cc-1))/2;}
    else{res-=(cc*(cc-1))/2;}
  }
  for(long long i=max(2ll,l);i<=r;i++){res-=(r/i-1);}
  cout << 2*res << '\\n';
  return 0;
}

以上是关于AtCoder Beginner Contest 206 E - Divide Both(容斥)的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242