[SDOI2014]数表

[SDOI2014]数表

一.题意简述

​ 题目要求的是

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

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

二.解题思路

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

\[\sum\limits_{d=1}^{n}\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sigma(d)[gcd(i,j)=1]\\ \]

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

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

\[\sum\limits_{d=1}^{n}\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sigma(d)\sum\limits_{k|gcd(i,j)}^{}\mu(k)\\ \]

然后走一波换位+基操

\[\sum\limits_{d=1}^{n}\sigma(d)\sum\limits_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k) \lfloor\frac{n}{dk}\rfloor\lfloor\frac{m}{dk}\rfloor\\ \]

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

\[(p=dk)\sum\limits_{p=1}^{n}\lfloor\frac{n}{p}\rfloor\lfloor\frac{m}{p} \rfloor\sum\limits_{d|p}^{}\mu(d)\sigma(\frac{p}{d}) \]

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

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

\[(p=dk)\sum\limits_{p=1}^{n}\lfloor\frac{n}{p}\rfloor\lfloor\frac{m}{p} \rfloor\sum\limits_{d|p}^{}\mu(d)\sigma(\frac{p}{d})\\ \sum\limits_{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;
}
posted @ 2020-02-03 17:25  clockwhite  阅读(135)  评论(0编辑  收藏  举报