HDU6265(能被n整除的因子与其欧拉乘积的和)

由这两个公式联立

公式很显然我们可以消去d可以推出:

我们知道对于每个pi,我们都有qi种取法,根据欧拉函数的性质我们知道每一个质数的的倍数的欧拉函数值 都等于这个质数的欧拉函数值等于其扩大的倍数,正好其外面缩小倍数也为其欧拉扩大的倍数,所以这组数对答案的贡献是相同的。

我们可以通过类比的方法得到所有的答案:我们可以通过已经给的质因子知道他一共有多少因子,通过欧拉函数的性质我们可以将对答案贡献相同的一起计算。

由例2为例:

质因子为 2 、3   指数都为2。

我们可以通过枚举取不取质因子来分析:   全不取:上式答案为 n本身,等于phi(1)*n。

取 第一个质因子2 ,      取一个   计算的是  phi[2]*(n/2);取两个   计算的就是 phi[4]*(n/4) 。你可以发现这两个结果是相同的,因为上面说的欧拉函数的性质。所以我们算只取一个质因子的时候要乘以qi,选择的数量。

取 第二个质因子3 ,     取一个    计算的就是  phi[3]*(n/3),取两个 计算的就是  phi[9]*(n/9)。你也知道这样个结果是相同的,所以我们可以一起计算。

取 两个质因子2和,      取一个 2和一个3    计算的就是   phi[6]*(n/6),取两个2和一个3   就是计算的    phi[12]*(n/12),取1个2和两个3就是计算的  phi[18]*(n/18),取两个2和两个3,就是计算的  phi[36]*(n/36);这几类的答案也是相同的,我们可以一起计算。

这样就将所有的因子枚举完全。即答案。

但是                  这道题时间复杂度卡常!!!!

图省事我用了以前容斥装压部分的板子,改了改没想到T了!

T的部分代码如下:

   for(int i=0;i<(1<<m);i++)
	    {
	    	ll res=x;
	    	for(int j=0;j<m;j++)
	    	{
	    	  if(i&(1<<j))
	    	   res=res*(p[j]-1)%mod*q[j]%mod*inv[j]%mod;
	        }
	    	ans=(ans+res)%mod;
	    }

不T的代码如下:

void dfs(ll pos,ll x){
	if(pos==m)
	{
		ans=(ans+x)%mod;
		return;
	}
	dfs(pos+1,x);
	dfs(pos+1,x*(p[pos]-1)%mod*q[pos]%mod*inv[pos]%mod);
}

仅仅比dfs多跑了一遍每个因子判断它取不取,只不多了一个常数20。真的惨!

代码如下:

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 25;
const int mod = 998244353;
using namespace std;
int p[maxn],q[maxn],inv[maxn],m;
ll ans;
ll pow_mod(ll a,ll b){
	ll res=1;
	while(b)
	{
		if(b&1) res=res*a%mod;
		b=b>>1;
		a=a*a%mod;
	}
	return res;
}
void init(int m){
	for(int i=0;i<m;i++)
	inv[i]=pow_mod(p[i],mod-2);
}
void dfs(ll pos,ll x){
	if(pos==m)
	{
		ans=(ans+x)%mod;
		return;
	}
	dfs(pos+1,x);
	dfs(pos+1,x*(p[pos]-1)%mod*q[pos]%mod*inv[pos]%mod);
}
int main()
{
	int t;
	ll x;
	scanf("%d",&t);
	while(t--)
	{
		ans=0;
		x=1;
		scanf("%d",&m);
		for(int i=0;i<m;i++)
		{
		 scanf("%d %d",&p[i],&q[i]);
		 x=x*pow_mod(p[i],q[i])%mod;
	    }
	    init(m);
	    dfs(0,x);
	    printf("%lld\n",ans);
	}
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值