P4450-雙親數,P5221-Product,P6055-[RC-02]GCD【莫比烏斯反演,杜教篩】
除了最後一題都比較簡單就寫一起了
P4450-雙親數
題目連結:https://www.luogu.com.cn/problem/P4450
題目大意
給出\(A,B,d\)求有多少對\((a,b)\)滿足\(gcd(a,b)=d\)且\(a\in[1,A],b\in[1,B]\)
解題思路
很顯然的容斥,列舉\(d\)的倍數\(i\),然後容斥係數就是\(\mu(\frac{i}{d})\)。
時間複雜度\(O(n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e6+10; int A,B,d,mu[N],pri[N],cnt; long long ans; bool v[N]; int main() { scanf("%d%d%d",&A,&B,&d); mu[1]=1; for(int i=2;i<N;i++){ if(!v[i])pri[++cnt]=i,mu[i]=-1; for(int j=1;j<=cnt&&i*pri[j]<N;j++){ v[i*pri[j]]=1; if(i%pri[j]==0)break; mu[i*pri[j]]=-mu[i]; } } if(A>B)swap(A,B); for(int i=d;i<=A;i+=d) ans+=1ll*(A/i)*(B/i)*mu[i/d]; printf("%lld\n",ans); }
P5221-Product
題目連結:https://www.luogu.com.cn/problem/P5221
題目大意
給出\(n\)求
\[\prod_{i=1}^n\prod_{j=1}^n\frac{lcm(i,j)}{gcd(i,j)} \]解題思路
\(\text{CYJian}\)的題啊,時限\(0.2s?\)不過只是看起來花裡胡哨,沒有其他\(\text{CYJian}\)的題那麼難。
先簡單把\(lcm\)拆出來化一下式子
\[\left(\prod_{i=1}^n\prod_{j=1}^ni\times j\right)\frac{1}{\left(\prod_{i=1}^{n}\prod_{j=1}^ngcd(i,j)\right)^2} \]左邊那個很容易求就是\((n!)^{2n}\),右邊那個因為是乘積所以很好做,直接列舉質數冪\(d^e\),讓有\(\lfloor\frac{n}{d^e}\rfloor^2\)對數的\(gcd\)包含\(d^e\),會產生這麼多的貢獻,但是因為在\(d^{e-1}\)的時候也統計過一次,所以只需要產生\(d\)的貢獻就好了。
時間複雜度\(O(n\log n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e6+10,P=104857601; ll n,ans,cnt,pri[N]; bool v[N]; ll power(ll x,ll b){ ll ans=1; while(b){ if(b&1)ans=ans*x%P; x=x*x%P;b>>=1; } return ans; } signed main() { scanf("%lld",&n);ans=1; for(ll i=2;i<=n;i++){ if(!v[i]){ for(ll j=i;j<=n;j=j*i) ans=ans*power(i,(n/j)*(n/j)%(P-1))%P; pri[++cnt]=i; } for(ll j=1;j<=cnt&&i*pri[j]<=n;j++){ v[i*pri[j]]=1; if(i%pri[j]==0)break; } } ans=power(ans*ans%P,P-2); ll f=1; for(ll i=1;i<=n;i++)f=f*i%P; f=power(f,2*n);ans=ans*f%P; printf("%lld",ans); return 0; }
P6055-[RC-02]GCD
題目連結:https://www.luogu.com.cn/problem/P6055
題目大意
給出\(n\)求
\[\sum_{i=1}^n\sum_{j=1}^n\sum_{p=1}^{\lfloor\frac{n}{j}\rfloor}\sum_{q=1}^{\lfloor\frac{n}{j}\rfloor}[gcd(i,j)=1][gcd(p,q)=1] \]解題思路
剛開始還以為可以直接暴力整除分塊+杜教篩尤拉函式然後\(O(n^{\frac{3}{4}})\)搞,然後發現時限是\(1s\)。
發現這個式子的順序很奇怪,特意的把\(j\)放在了裡面。這個提示我們\(j\)其實是在列舉\(p\)和\(q\)的\(gcd\)。
而又\(j\)和\(i\)互質,其實這個式子的真正目的是對於每個\(i\)求有多少對數的\(gcd\)和\(i\)互質然後求和。換成式子就是
就是三對數之間互質的對數,之間上莫反就可以了
\[\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor^3\mu(i) \]\(n\)比較大,要用杜教篩篩一下\(mu\)
時間複雜度\(O(n^{\frac{2}{3}})\)?
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
const ll N=1e7+10,P=998244353;
ll n,cnt,pri[N],mu[N],ans;
map<ll,ll> mp;
bool v[N];
ll get_sum(ll n){
if(mp.find(n)!=mp.end())return mp[n];
if(n<N)return mu[n];
ll rest=1;
for(ll l=2,r;l<=n;l=r+1)
r=n/(n/l),(rest+=P-(r-l+1)*get_sum(n/l))%=P;
return mp[n]=rest;
}
signed main()
{
scanf("%lld",&n);mu[1]=1;
for(ll i=2;i<N;i++){
if(!v[i])pri[++cnt]=i,mu[i]=-1;
for(ll j=1;j<=cnt&&i*pri[j]<N;j++){
v[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(ll i=1;i<N;i++)(mu[i]+=mu[i-1])%=P;
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);
ll p=n/l;p=p*p%P*p%P;
(ans+=p*(get_sum(r)-get_sum(l-1))%P)%=P;
}
printf("%lld\n",(ans+P)%P);
return 0;
}