1. 程式人生 > >51nod 1439 互質對

51nod 1439 互質對

題目連結

題意:

N 個數,然後 Q 次詢問,每次詢問一個 id ,如果這個 id 沒有出現過,就在集合中新增一個 a[id] ,如果出現過就把 a[id] 刪去,換句話說,就是每個下標只能選或者不選,但是裡面的數重複不重複無所謂,然後每次操作完詢問集合裡面互質的對數有多少種

思路:

我看的這個部落格是計算每次加進去或取出來的這個數,與當前集合互質的對數 但是怎麼求喃?這個是個關鍵: 根據部落格的意思:add=μ(1)含有因子1的個數+μ(2)含有因子2的個數+μ

(3)含有因子3的個數+μ(4)含有因子4的個數+…+… 也就是說假如這個數 x 含有因子 d1,d2,d3,d4…. add=+μ(d1)含有因子 d1 的個數+μ(d2)含有因子 d2 的個數+μ(d3)含有因子 d3 的個數+μ(d4)含有因子 d4 的個數

然後我還學到了一個 NlogN 篩出每個數所有的因子的方法,嘿嘿嘿~

#include"bits/stdc++.h"
using namespace std;
typedef long long LL;
const
int maxn=5e5+5; const int MOD=1e9+7; int Fac[maxn],a[maxn];//Fac[i]表示i這個因子有多少個 vector<int>prime,factor[maxn]; bool vis[maxn]; int mu[maxn]; void PHI(int n) { memset(vis,1,sizeof(vis)); mu[1]=1; for(LL i=1;i<=n;i++) { for(LL j=1;i*j<=n;j++)//篩因子 { factor[i*j].push_back(j); } if
(i==1)continue;//篩質數要從2開始 if(vis[i]) { prime.push_back(i); mu[i]=-1; } for(LL j=0;j<prime.size()&&i*prime[j]<=n;j++) { vis[i*prime[j]]=0; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else mu[i*prime[j]]=-mu[i]; } } } bool has[maxn];//來看下標為i的出現過沒得 int main() { PHI(maxn-5); int N,M; while(cin>>N>>M) { memset(Fac,0,sizeof Fac); memset(has,0,sizeof has); LL ans=0; for(int i=1;i<=N;i++)scanf("%d",a+i); while(M--) { int id,t; scanf("%d",&id); t=a[id]; int d; if(has[id]) { for(int j=0;j<factor[t].size();j++)d=factor[t][j],Fac[d]--; for(int j=0;j<factor[t].size();j++)d=factor[t][j],ans-=mu[d]*Fac[d]; } else { for(int j=0;j<factor[t].size();j++)d=factor[t][j],ans+=mu[d]*Fac[d]; for(int j=0;j<factor[t].size();j++)d=factor[t][j],Fac[d]++; } has[id]^=1; cout<<ans<<endl; } } }