P3312 [SDOI2014]数表

https://www.luogu.org/problemnew/show/P3312

比较nb的一个题。

首先考虑没有a的限制怎么搞。

把d提到前面

mobius反演一下

令T=dx,把T挪到前面(没想到这一步!)

设F(x)=d(x)和mu(x)的狄利克雷卷积。

然后考虑怎么带上a的限制,只要能动态维护F(x)即可sqrt(n)*O(维护复杂度)解决本题。

考虑把询问离线,并把d(x)按照权值排序,逐一加入,加入第i项后,它会对F(x)中为i的倍数的项产生一个d(i)✖mu(x/i)的贡献。

有发现除法分块求答案时,需要用到F(x)的区间和。

因此用树状数组维护一下即可。

#include<bits/stdc++.h>
#define N 220000
#define L 200000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline int read()
{
	char ch=0;
	int x=0,flag=1;
	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*flag;
}
bool is_prime[N];
int c[N],p[N],d[N],mu[N],prime[N];
void solve(int n)
{
	memset(is_prime,true,sizeof(is_prime));
	is_prime[0]=is_prime[1]=false;
	c[0]=c[1]=p[0]=p[1]=d[0]=d[1]=mu[0]=mu[1]=1;
	for(int i=2,cnt=0;i<=n;i++)
	{
		if(is_prime[i])c[i]=p[i]=i,prime[++cnt]=i;
		for(int j=1;j<=i;j++)
		{
			int t=i*prime[j];
			if(t>n)break;
			is_prime[t]=false;
			if(i%prime[j])c[t]=p[t]=prime[j];
			else c[t]=prime[j],p[t]=p[i]*prime[j];
			if(i%prime[j]==0)break;
		}
	}
	for(int i=2;i<=n;i++)
	if(i==p[i])
	{
		if(is_prime[i])d[i]=1+i,mu[i]=-1;
		else d[i]=d[i/c[i]]+i,mu[i]=0;
	}
	else
	{
		int j=p[i];
		d[i]=d[j]*d[i/j];
		mu[i]=mu[j]*mu[i/j];
	}
}
struct node{int x,id;}f[N];
bool cmp_node(node a,node b){return a.x<b.x;}
struct query{int n,m,k,id;}q[N];
bool cmp_query(query a,query b){return a.k<b.k;}
int t,cnt,len,s[N],ans[N];
void add(int x,int k){for(;x<=len;x+=((+x)&(-x)))s[x]+=k;}
int get(int l,int r)
{
	int x,ans=0;
	for(x=l-1;x;x-=((+x)&(-x)))ans-=s[x];
	for(x=r+0;x;x-=((+x)&(-x)))ans+=s[x];
	return ans;
}
int main()
{
	t=read();len=1e5;solve(len);
	for(int i=1;i<=len;i++)f[i]={d[i],i};sort(f+1,f+len+1,cmp_node);
	for(int i=1;i<=t;i++)
	{
		int n=read(),m=read(),x=read();
		if(x>=0)q[++cnt]={n,m,x,i};
	}
	sort(q+1,q+t+1,cmp_query);
	for(int i=1,j=0;i<=cnt;i++)
	{
		while(j!=len&&f[j+1].x<=q[i].k)
		{
			j++;
			for(int k=f[j].id;k<=len;k+=f[j].id)add(k,f[j].x*mu[k/f[j].id]);
		}
		int n=q[i].n,m=q[i].m; 
		for(int l=1,r;l<=min(n,m);l=r+1)
		{
			r=min(n/(n/l),m/(m/l));			
			ans[q[i].id]+=(n/l)*(m/l)*get(l,r);
		}		
	}
	
	for(int i=1;i<=t;i++)
	{
		ll x=ans[i],p=1ll<<31;
		printf("%lld\n",(x%p+p)%p);
	}
	return 0;
}
posted @ 2019-03-31 21:15  Creed-qwq  阅读(165)  评论(0编辑  收藏  举报