由这两个公式联立
公式很显然我们可以消去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;
}