数表[BZOJ3529]\[SDOI2014]

版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89788385

欢迎大家访问我的老师的OJ———caioj.cn

题面描述

传送门

思路

先%一波dalao——PoPoQQQ

话说这道题真的毒瘤啊!

一句话题意,设 f ( i ) f(i) i i 的约数和,求 a n s = i = 1 n j = 1 m f ( gcd ( i , j ) ) < = a f ( gcd ( i , j ) ) mod 2 31 \large ans=\sum_{i=1}^n\sum_{j=1}^{m并且f(\gcd(i,j))<=a}f(\gcd(i,j))\operatorname{mod}2^{31}

假设现在先无 a a 这个限制条件。

Zap(务必看一看)可知, 1 i n , 1 j n , gcd ( i , j ) = k 1\le i\le n,1\le j\le n,\gcd(i,j)=k 可以转化为 1 i n / k , 1 j n , gcd ( i , j ) = 1 1\le i\le n/k,1\le j\le n,\gcd(i,j)=1 ,我们设 g ( i ) g(i) 表示满足 x n , y m x\le n,y\le m 并且 gcd ( x , y ) = i \gcd(x,y)=i 的二元组有多少对,显然
g ( i ) = F ( n / i , m / i ) = j = 1 min ( n / i , m / i ) μ ( j ) D ( n / i , m / i , j ) \large g(i)=F(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor)=\sum_{j=1}^{\min(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor)}\mu(j)*D(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor,j)
g ( i ) = j = 1 min ( n / i , m / i ) μ ( j ) n / i / j m / i / j \large g(i)=\sum_{j=1}^{\min(\left\lfloor\\n/i\right\rfloor,\left\lfloor\\m/i\right\rfloor)}\mu(j)*\left\lfloor\\ \left\lfloor\\n/i\right\rfloor/j\right\rfloor*\left\lfloor\\ \left\lfloor\\m/i\right\rfloor/j\right\rfloor

d = i j d=i*j ,有
g ( i ) = i d min ( n , m ) μ ( d i ) n / d m / d \large g(i)=\sum_{i|d}^{\min(n,m)}\mu(\frac{d}{i})*\left\lfloor\\ n/d\right\rfloor*\left\lfloor\\ m/d\right\rfloor

所以 a n s = i = 1 m i n ( n , m ) g ( i ) f ( i ) = i = 1 m i n ( n , m ) i d min ( n , m ) μ ( d i ) n / d m / d f ( i ) \large ans=\sum_{i=1}^{min(n,m)}g(i)f(i)=\sum_{i=1}^{min(n,m)}\sum_{i|d}^{\min(n,m)}\mu(\frac{d}{i})*\left\lfloor\\ n/d\right\rfloor*\left\lfloor\\ m/d\right\rfloor* f(i)

= d = 1 min ( n , m ) n / d m / d i d m i n ( n , m ) μ ( d i ) f ( i ) =\large\sum_{d=1}^{\min(n,m)}\left\lfloor\\ n/d\right\rfloor*\left\lfloor\\ m/d\right\rfloor\sum_{i\mid d}^{min(n,m)}\mu(\frac{d}{i})*f(i)

预先处理一下, f ( i ) f(i) 数组。

所以没有限制条件 a a 下的答案,就如上所求。

我们只要排序一下 a a 就行了。

那么有限制条件 a a 时,我们要多开一个树状数组,并将 f ( i ) f(i) 排序。

每次询问时,进行相应操作即可。

AC code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define gc getchar()
using namespace std;
const int M=4e4+10;
const int N=1e5+10;
inline void qr(int &x)
{
	x=0;int f=1;char c=gc;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
	x*=f;
}
void qw(int x)
{
	if(x<0)x=-x,putchar('-');
	if(x/10)qw(x/10);
	putchar(x%10+48);
}
int Q,mx,m;
struct data{int n,m,a,id;}q[M];int ans[M];
bool v[N];int prime[N],mu[N],c[N];
bool cmp1(data a,data b){return a.a<b.a;}
struct node{int sum,id;}f[N];
bool cmp2(node a,node b){return a.sum<b.sum;}
void add(int x,int y){for(;x<=mx;x+=x&-x)c[x]+=y;}
int ask(int x)
{
	int tmp=0;
	for(;x;x-=x&-x)tmp+=c[x];
	return tmp;
}
void pre()
{
	mu[1]=1;m=0;
	for(int i=2;i<=mx;i++)
	{
		if(!v[i])prime[++m]=i,mu[i]=-1;
		for(int j=1;j<=m&&prime[j]*i<=mx;j++)
		{
			v[i*prime[j]]=1;
			if(i%prime[j]==0){mu[i*prime[j]]=0;break;}
			mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=mx;i++)
		for(int j=i;j<=mx;j+=i)
			f[j].sum+=i;
	for(int i=1;i<=mx;i++)f[i].id=i;
}
void solve(int i)
{
	int id=q[i].id,n=q[i].n,m=q[i].m;
	for(int x=1,gx;x<=n;x=gx+1)
	{
		gx=min(n/(n/x),m/(m/x));
		ans[id]+=(ask(gx)-ask(x-1))*(n/x)*(m/x);
	}
}
int main()
{
	qr(Q);
	for(int i=1;i<=Q;i++)
	{
		qr(q[i].n),qr(q[i].m),qr(q[i].a),q[i].id=i;
		if(q[i].n>q[i].m)swap(q[i].n,q[i].m);
		mx=max(mx,q[i].n);
	}
	pre();
	sort(q+1,q+Q+1,cmp1);
	sort(f+1,f+mx+1,cmp2);
	int now=0;
	for(int i=1;i<=Q;i++)
	{
		while(now+1<=mx&&f[now+1].sum<=q[i].a)
		{
			now++;
			for(int j=f[now].id;j<=mx;j+=f[now].id)
				add(j,f[now].sum*mu[j/f[now].id]);
		}
		solve(i);
	}
	for(int i=1;i<=Q;i++)
		qw(ans[i]&0x7fffffff),puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zyszlb2003/article/details/89788385