由這兩個公式聯立
公式很顯然我們可以消去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;
}