NOIP模拟赛20191112 T3 c【推式子(莫比乌斯反演)】

题目描述:

求:
∑ d ∣ n , d ∣ s ∑ g ∣ n d μ ( g ) ∗ ⌊ m d g ⌋ \sum_{d|n,d|s}\sum_{g|\frac nd}\mu(g)*\lfloor\frac m{dg}\rfloor dn,dsgdnμ(g)dgm
其中 n , m , s n,m,s n,m,s满足 { n = n 1 ⋅ n 2 ⋅ n 3 m = m 1 ⋅ m 2 ⋅ m 3 s = s 1 ⋅ s 2 ⋅ s 3 \begin{cases}n=n_1\cdot n_2\cdot n_3\\m=m_1\cdot m_2\cdot m_3\\s=s_1\cdot s_2\cdot s_3\end{cases} n=n1n2n3m=m1m2m3s=s1s2s3
多组数据,数据组数 ≤ 1000 \le1000 1000 n 1 , n 2 , n 3 , m 1 , m 2 , m 3 , s 1 , s 2 , s 3 ≤ 1 0 6 n_1,n_2,n_3,m_1,m_2,m_3,s_1,s_2,s_3\le10^6 n1,n2,n3,m1,m2,m3,s1,s2,s3106

题目分析:

看到这个东西并且联想到NOIP的标题以及yali标准的模拟赛样式就明白这一定是把莫比乌斯反演的式子推到某一步进行了奇奇怪怪的变换然后拿来恶心人防AK。

于是我们开始按照题解推式子:
∑ d ∣ n , d ∣ s ∑ g ∣ n d μ ( g ) ∗ ⌊ m d g ⌋ \sum_{d|n,d|s}\sum_{g|\frac nd}\mu(g)*\lfloor\frac m{dg}\rfloor dn,dsgdnμ(g)dgm
首先把 μ \mu μ函数的系数想办法搞掉:
∑ d ∣ n , d ∣ s ∑ g ∣ n d ∑ i = 1 ⌊ m d g ⌋ μ ( g ) \sum_{d|n,d|s}\sum_{g|\frac nd}\sum_{i=1}^{\lfloor\frac m{dg}\rfloor}\mu(g) dn,dsgdni=1dgmμ(g)
联想到 ∑ g ∣ k μ ( g ) = [ k = 1 ] \sum_{g|k}\mu(g)=[k=1] gkμ(g)=[k=1],把第二个∑放到里层,原来的后两式相当于枚举 ⌊ m d ⌋ {\lfloor\frac m{d}\rfloor} dm中g的倍数,转换一下可变为:
∑ d ∣ n , d ∣ s ∑ i = 1 ⌊ m d ⌋ ∑ g ∣ n d , g ∣ i μ ( g ) \sum_{d|n,d|s}\sum_{i=1}^{\lfloor\frac m{d}\rfloor}\sum_{g|\frac nd,g|i}\mu(g) dn,dsi=1dmgdn,giμ(g)
整除两个数就相当于整除它们的gcd,于是:
∑ d ∣ n , d ∣ s ∑ i = 1 ⌊ m d ⌋ [ g c d ( i , n d ) = 1 ] \sum_{d|n,d|s}\sum_{i=1}^{\lfloor\frac m{d}\rfloor}[gcd(i,\frac nd)=1] dn,dsi=1dm[gcd(i,dn)=1]
先不看 d ∣ s d|s ds的条件,观察式子,发现其实 d d d就是在枚举 [ 1 , m ] [1,m] [1,m]中的数与 n n n g c d gcd gcd,如果没有 d ∣ s d|s ds的条件,则式子就 = m =m =m
现在加上 d ∣ s d|s ds的条件,那么只有与 n n n g c d gcd gcd s s s的约数的数会被统计到,即:
∑ i = 1 m [ g c d ( i , n ) ∣ s ] \sum_{i=1}^{m}[gcd(i,n)|s] i=1m[gcd(i,n)s]
到这里可以 O ( m log ⁡ m ) O(m\log m) O(mlogm)枚举计算,结合部分分拿到70分。
在这里插入图片描述
Code:

#include<bits/stdc++.h>
#define LL long long
#define x first
#define y second
using namespace std;
int T,num,bit[1<<15];
LL n,m,s,ans,f[1<<15];
vector<pair<int,int> >a,b;
void Divide(int x,vector<pair<int,int> >&q){
	for(int i=q.size()-1;i>=0;i--) while(x%q[i].x==0) q[i].y++,x/=q[i].x;
	for(int i=2;i*i<=x;i++) if(x%i==0){
		q.push_back(make_pair(i,0));
		while(x%i==0) q.back().y++,x/=i;
	}
	if(x>1) q.push_back(make_pair(x,1));
}
int main()
{
	//freopen("c.in","r",stdin);
	//freopen("c.out","w",stdout);
	scanf("%d",&T);
	while(T--){
		n=m=s=1,ans=num=0,a.clear(),b.clear();
		for(int i=0,x;i<3;i++) scanf("%d",&x),Divide(x,a);
		for(int i=0,x;i<3;i++) scanf("%d",&x),m*=x;
		for(int i=0,x;i<3;i++) scanf("%d",&x),Divide(x,b);
		sort(a.begin(),a.end()),sort(b.begin(),b.end());
		for(int i=0,j=0;i<a.size();i++){
			while(j<b.size()&&b[j].x<a[i].x) j++;
			if(j==b.size()||b[j].x>a[i].x||b[j].y<a[i].y){
				f[1<<num]=a[i].x;int ed=j==b.size()||b[j].x>a[i].x?0:b[j].y;
				for(int k=1;k<=ed;k++) f[1<<num]*=a[i].x;
				num++;
			}
		}
		ans=m,f[0]=1;
		for(int s=1;s<1<<num;s++){
			bit[s]=bit[s>>1]+(s&1);
			f[s]=f[s^(s&-s)]*f[s&-s];
			ans+=(bit[s]&1?-1:1)*m/f[s];
		}
		printf("%lld\n",ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值