[SDOI2014]数表

[SDOI2014]数表

一.题意简述

​ 题目要求的是

[sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}sigma(gcd(i,j))<a\ ]

那个是除数函数啦。(不知道的自己百度)

二.解题思路

​ 有什么思路,干就完了,奥利给!!这个(<a)很碍眼,反手扔了不虚他。于是要求解

[sumlimits_{d=1}^{n}sumlimits_{i=1}^{lfloorfrac{n}{d} floor} sumlimits_{j=1}^{lfloorfrac{m}{d} floor}sigma(d)[gcd(i,j)=1]\ ]

虽说这一步跨度有点大,但是是可以理解的,对于大多数gcd都会选择起手枚举gcd的值,而这里的(i,j)相当于是系数一样的东西叭。由于是枚举的最大公约数,所以(i,j)要互质才好,这是常规操作。

现在发现了一只野生的(epsilon),(如果读不懂这句话请先看这篇文章),那么就把他换成(mu).(基操)

[sumlimits_{d=1}^{n}sumlimits_{i=1}^{lfloorfrac{n}{d} floor} sumlimits_{j=1}^{lfloorfrac{m}{d} floor}sigma(d)sumlimits_{k|gcd(i,j)}^{}mu(k)\ ]

然后走一波换位+基操

[sumlimits_{d=1}^{n}sigma(d)sumlimits_{k=1}^{lfloorfrac{n}{d} floor}mu(k) lfloorfrac{n}{dk} floorlfloorfrac{m}{dk} floor\ ]

其实这里也是在枚举gcd,跟上面思路差不多,再不想让d干扰,换了个位置。

[(p=dk)sumlimits_{p=1}^{n}lfloorfrac{n}{p} floorlfloorfrac{m}{p} floorsumlimits_{d|p}^{}mu(d)sigma(frac{p}{d}) ]

乘积形式的分母不好看,换一手元,交换位置。

本来这样就好了,但是题目有个a。于是想着怎么把他找回来,加进去吧

[(p=dk)sumlimits_{p=1}^{n}lfloorfrac{n}{p} floorlfloorfrac{m}{p} floorsumlimits_{d|p}^{}mu(d)sigma(frac{p}{d})\ sumlimits_{d|p}^{}mu(d)sigma(frac{p}{d})<a ]

这个应该能看懂,首先以求和符号作为分界记后面的那一堆为(g(p))好了,然后考虑一下(mu)函数的性质,了解到(sigma(frac{p}{d})<=a)才对答案有贡献,然而又有多组数据,并且除数函数值的大小跟参数大小没有什么关系,是乱的。(开始暴躁)

不过不慌,我们把(sigma)和a都拉来排个序,新的a出现时便用符合条件的(sigma)去更新(g),再用数论分块算一算。(还是看代码吧)

三.CODE

#define ll long long
#define m_for(i,a,b) for(int i=a;i<=b;++i)
#define lowbit(x) x&(-x)
inline int read() {
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int MAXN=1e5+1,MAXQ=2*1e4+1;
ll mod=1LL<<31;
int prime[MAXN],tot,mu[MAXN];
ll g[MAXN];
pair<int,int> sigma[MAXN];
bool vis[MAXN];
void m_p(int x){
	sigma[1].first=sigma[1].second=1;
	mu[1]=1;
	m_for(i,2,x){
		sigma[i].first++;
		if(!vis[i])prime[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&i*prime[j]<=x;++j){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)break;
			mu[i*prime[j]]=-mu[i];
		}
		for(int j=i;j<=x;j+=i)sigma[j].first=(sigma[j].first+i)%mod;
		sigma[i].second=i;
	}
	sort(sigma+1,sigma+x+1);
}
struct alf{
	int n,m,a,id;
}que[MAXQ];
bool cmp(alf c,alf b){
	return c.a<b.a;
}
int tree_g[MAXN];
void change(int x,int y){
	for(;x<MAXN;x+=lowbit(x))tree_g[x]+=y;
}
ll sum(int x){
	ll res=0;
	for(;x>0;x-=lowbit(x))res+=tree_g[x];
	return res;
}
ll solve(int n,int m){
	if(n>m)swap(n,m);
	ll res=0;
	for(int l=1,r;l<=n;l=r+1){
		r=min(n/(n/l),m/(m/l));
		res+=1LL*(n/l)*(m/l)*(sum(r)-sum(l-1));
		res%=mod;
	}
	return (res%mod+mod)%mod;
}
int q,res=1;
int ans[MAXQ];
int main(){
m_p(MAXN);
q=read();
m_for(i,1,q)que[i].id=i,que[i].n=read(),que[i].m=read(),que[i].a=read();
sort(que+1,que+q+1,cmp);
m_for(i,1,q){
	while(sigma[res].first<=que[i].a&&res<=MAXN){
		for(int j=1;j*sigma[res].second<=MAXN;++j)
			change(j*sigma[res].second,mu[j]*sigma[res].first);
		res++;
	}
	ans[que[i].id]=solve(que[i].n,que[i].m)%mod;
}
m_for(i,1,q)cout<<ans[i]<<endl;
return 0;
}
原文地址:https://www.cnblogs.com/clockwhite/p/12256469.html