luoguP3312 数表

智障如我

看题解看了半天才懂

其实就是一道莫比乌斯反演+离线处理+树状数组维护前缀和的题目

上代码

#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
	typedef long long ll;
	typedef double db;
	const db PI=acos(-1.0);
	#define cp complex<db>
	#define MP make_pair
	#define fir first
	#define sec second
	#define fr(i,x,y) for(int i=(x);i<=(y);i++)
	#define pfr(i,x,y) for(int i=(y);i>=(x);i--)
	#define gfr(u) for(int i=head[u];i;i=e[i].nxt)
	#define pf printf
	//#define v e[i].to
	//#define w e[i].w
	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;
	}
}
using namespace my_std;
const ll N=1e5+50;
int q,tmp,maxn,cnt,pri[100005],miu[100005],mark[N],tree[100005],ans[40005];
struct haha
{
	int n,m,a,id;
}ask[N];
pair<int,int> sig[100005];//约数和 
bool operator<(haha a,haha b)
{
	return a.a<b.a;
}
inline int lowbit(int x)
{
	return x&(-x);
}
inline void add(int x,int val)
{
	for(int i=x;i<=maxn;i+=lowbit(i)) tree[i]+=val;
}
inline int query(int x)
{
	int tmp=0;
	for(int i=x;i;i-=lowbit(i))
	{
		tmp+=tree[i];
	}
	return tmp;
}
inline void solve(int x)//dead
{
	int id=ask[x].id,n=ask[x].n,m=ask[x].m;
	for(int i=1,j;i<=ask[x].n;i=j+1)
	{
		j=min(n/(n/i),m/(m/i));
		//pf("alive before query
");
		ans[id]+=(n/i)*(m/i)*(query(j)-query(i-1));
	}
}
inline void cal_miu()
{
	miu[1]=1;
	for(int i=2;i<=maxn;i++)
	{
		if(!mark[i]) pri[++cnt]=i,miu[i]=-1;
		for(int j=1;j<=cnt&&pri[j]*i<=maxn;j++)
		{
			mark[pri[j]*i]=1;
			if(i%pri[j]==0)
			{
				miu[pri[j]*i]=0;
				break;
			}
			else miu[pri[j]*i]=-miu[i];
		}
	}
}
inline void cal_sig()
{
	for(int i=1;i<=maxn;i++)
	{
		for(int j=i;j<=maxn;j+=i)
		{
			sig[j].first+=i; 
		} 
	} 
	for(int i=1;i<=maxn;i++)
	{
		sig[i].second=i;
	}
}
int main(void)
{
	q=read();
	for(int i=1;i<=q;i++)
	{
		ask[i].n=read(),ask[i].m=read(),ask[i].a=read(),ask[i].id=i;
		if(ask[i].n>ask[i].m) swap(ask[i].n,ask[i].m);
		maxn=max(maxn,ask[i].n);
	}
	cal_miu();
	cal_sig();
	sort(ask+1,ask+q+1);
	sort(sig+1,sig+maxn+1);
	for(int i=1;i<=q;i++)
	{
		while(tmp+1<=maxn&&sig[tmp+1].first<=ask[i].a)
		{
			tmp++;
			for(int j=sig[tmp].second;j<=maxn;j+=sig[tmp].second)
			{
				add(j,sig[tmp].first*miu[j/sig[tmp].second]);
			}
		}
		solve(i);
	}
	for(int i=1;i<=q;i++)
	{
		printf("%d
",ans[i]&(~(1<<31)));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lgj-lgj/p/12237827.html