洛谷P2522

题目链接

(Solution:)

建议先写这道以获得双倍经验
所以在它的基础上加一个前缀和即可

(Code:)

#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
	typedef long long ll;
	#define fr(i,x,y) for(ll i=(x);i<=(y);i++)
	#define pfr(i,x,y) for(ll i=(y);i>=(x);i--)
	inline ll read()
	{
		ll sum=0,f=1;
		char ch=0;
		while(!isdigit(ch))
		{
			if(ch=='-') f=-1;
			ch=getchar();
		}
		while(isdigit(ch))
		{
			sum=(sum<<1)+(sum<<3)+(ch^48);
			ch=getchar();
		}
		return sum*f;
	}
	inline void write(ll x)
	{
	    if(x<0)
		{
	    	putchar('-');
			x=-x;
		}
	    if(x>9) write(x/10);
	    putchar(x%10+'0');
	}
}
using namespace my_std;
const ll N=5e4+50,hahaha=50000;
ll miu[N],sum[N],pri[N],mark[N],tot;
inline void cal_miu()
{
	miu[1]=1;
	for(ll i=2;i<=hahaha;i++)
	{
		if(!mark[i])pri[++tot]=i,miu[i]=-1;
		for(ll j=1;j<=tot&&i*pri[j]<=hahaha;j++)
		{
			mark[i*pri[j]]=1;
			if(i%pri[j]==0){miu[i*pri[j]]=0;break;}
			else miu[i*pri[j]]=-miu[i];
		}
	}
	for(ll i=1;i<=hahaha;i++)
	{
		sum[i]=sum[i-1]+miu[i];
	}
}
inline ll solve(ll n,ll m)
{
	if(n>m)swap(n,m);
	ll ans=0,pos;
	for(ll i=1;i<=n;i=pos+1)
	{
		pos=min(n/(n/i),m/(m/i));
		ans+=(sum[pos]-sum[i-1])*(n/i)*(m/i);
	}
	return ans;
}
int main(void)
{
	cal_miu();
	ll qwq=read();
	while(qwq--)
	{
		ll a=read(),b=read(),c=read(),d=read(),k=read();
		a--;c--;
		int ans=solve(a/k,c/k)+solve(b/k,d/k)-solve(a/k,d/k)-solve(b/k,c/k);
		write(ans);
		putchar('
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lgj-lgj/p/12335060.html