hdu1695 bzoj2301 (Mobius inversion)

hdu1695

Meaning of the questions beg:ans=\sum_{i=1}^{n}\sum_{j=1}^{m}(gcd(i,j)=k)

Ideas: see gcd sum equation basically Mobius inversion.

Then we divided the original type k, it becomes ans=\sum_{i=1}^{n/k}\sum_{j=1}^{m/k}(gcd(i,j)=1),

We set f [k] = (gcd (i, j) = k), F [x] = (k | gcd (i, j)). Then we find ans = f [1]. Easy to get F [k] = (n / i) * (m / k)

Using a second formula, inversion Mobius

 

and sof[1]=\sum_{i=1}^{}\mu(i)*(n/i)*(m/i)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1e9+7;
const ll maxn=100010;
ll vis[maxn];
ll prime[maxn];
ll cnt;
ll mu[maxn];
ll sum[maxn];
void init()
{
	memset(vis,0,sizeof(vis));
	cnt=0;mu[1]=1;
	for(ll i=2;i<=maxn;i++)
	{
		if(!vis[i]) prime[cnt++]=i,mu[i]=-1;
		for(ll j=0;j<cnt&&prime[j]*i<=maxn;j++)
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0;break;
			}
			else
			{
				mu[i*prime[j]]=-mu[i];
			}
		}
	}
	sum[0]=0;
	for(ll i=1;i<maxn;i++) sum[i]=sum[i-1]+mu[i];
}

int main()
{
	ll a,b,c,d,k;
	init();
	ll T;scanf("%lld",&T);ll cas=0;
	while(T--)
	{
		cas++;
		scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
		cout<<"Case "<<cas<<": ";
		if(k==0) cout<<0<<endl;
		else
		{
			b/=k;d/=k;
			if(b>d) swap(b,d);
			ll ans1=0;ll last=1;
			for(ll i=1;i<=min(b,d);i=last+1)		//整数分块 
			{
				last=min(b/(b/i),d/(d/i));
				ans1+=(sum[last]-sum[i-1])*(b/i)*(d/i);
			}
			ll ans2=0;
			last=1;
			for(ll i=1;i<=b;i=last+1)				//整数分块 
			{
				last=b/(b/i);
				ans2+=(sum[last]-sum[i-1])*(b/i)*(b/i);
			}
			printf("%lld\n",ans1-ans2/2);			
		}
	}
	return 0;
}

 bzoj2301

Meaning of the questions above, and a similar problem, seek ans=\sum_{i=a}^{b}\sum_{j=c}^{d}(gcd(i,j)=k), note the difference between this question and the question, is no longer the interval from the beginning, and (x, y) and (y, x) for all the answers contribution 1.

Ibid., After inversion requires the inclusion-exclusion. Provided solve (x, y, k) ofans=\sum_{i=1}^{x}\sum_{j=1}^{y}(gcd(i,j)=k)

The answer is solve (b, d, k) -solve (a-1, d, k) -solve (b, c-1, k) + solve (a-1, c-1, k)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1e9+7;
const ll maxn=100010;
ll vis[maxn];
ll prime[maxn];
ll cnt;
ll mu[maxn];
ll sum[maxn];
void init()
{
	memset(vis,0,sizeof(vis));
	cnt=0;mu[1]=1;
	for(ll i=2;i<=maxn;i++)
	{
		if(!vis[i]) prime[cnt++]=i,mu[i]=-1;
		for(ll j=0;j<cnt&&prime[j]*i<=maxn;j++)
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				mu[i*prime[j]]=0;break;
			}
			else
			{
				mu[i*prime[j]]=-mu[i];
			}
		}
	}
	sum[0]=0;
	for(ll i=1;i<maxn;i++) sum[i]=sum[i-1]+mu[i];
}
ll solve(ll b, ll d,ll k)
{
	b/=k;d/=k;	
	if(b>d) swap(b,d);
	ll ans1=0;
	ll last=1;
	for(ll i=1;i<=min(b,d);i=last+1)		//整数分块 
	{
		last=min(b/(b/i),d/(d/i));
		ans1+=(sum[last]-sum[i-1])*(b/i)*(d/i);
	}
	ll ans2=0;
	last=1;
	for(ll i=1;i<=b;i=last+1)				//整数分块 
	{
		last=b/(b/i);
		ans2+=(sum[last]-sum[i-1])*(b/i)*(b/i);
	}
	return ans1;	
}
int main()
{
	ll a,b,c,d,k;
	init();
	ll T;scanf("%lld",&T);ll cas=0;
	while(T--)
	{
		cas++;
		scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
		if(k==0) cout<<0<<endl;
		else
		{
			ll ans=solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k);
			printf("%lld\n",ans);
		}
	}
	return 0;
}

 

Published 155 original articles · won praise 32 · views 30000 +

Guess you like

Origin blog.csdn.net/qq_37632935/article/details/88553550