解題報告: Codeforces Round #305 (Div. 2) E.Mike and Foam (莫比烏斯反演)

題目鏈接


題意:

有一個長度爲n(n<=2e5)的序列,q(q<=2e5)次操作

序列中的每個位置對應一個數ai(1<=ai<=5e5)

每次操作給一個數x,代表挑出的序列中的下標爲x的數

若對應下標的數已經被挑出,那麼就把它放回去

每次操作完,詢問所有挑出的數中互質的對數

剛開始時所有數都沒有被挑出


思路:

剛開始的沒有數被挑出,那麼初始答案爲0。

令num[i] :挑出的數中 i 的個數

如果當前操作的數爲x,那麼對答案的貢獻

如果是挑出則加,放入則減,注意x==1的情況

反演一下貢獻的式子:

轉化枚舉量:

到這裏可以發現,預處理每個數的有效因子,用樹狀數組維護每個d的前綴和

就能在更新答案和前綴和



代碼:

#include<bits/stdc++.h>


#define lowbit(x) (x&(-x))
const int N = 5e5+10;
using namespace std;

vector<int>pr,fro[N],E[N];
bool Np[N];
int mu[N];

void init(){
   mu[1] = 1;
   for(int i=2;i<N;i++){
      if(!Np[i]){
         mu[i] = -1;
         pr.emplace_back(i);
      }for(int j=0,k=pr[0]*i;k<N;k=pr[++j]*i){
         Np[k] = true;
         if(i%pr[j]==0){
            mu[k] = 0;
            break;
         }mu[k] = -mu[i];
      }
   }for(int i=1;i<N;i++)if(mu[i]){
      fro[i].emplace_back(0);
      for(int j=i;j<N;j+=i){
         E[j].emplace_back(i);
         fro[i].emplace_back(0);
      }
   }
}



inline void add(int d,int x,int val){
   int n = fro[d].size();
   while(x<n){
      fro[d][x]+=val;
      x += lowbit(x);
   }
}

inline long long query(int d,int x){
   long long res = 0;
   while(x){
      res += fro[d][x];
      x -= lowbit(x);
   }return res;
}


long long work(int x){
   long long res = 0;
   for(int i=0;i<E[x].size();i++){
      int d = E[x][i];
      long long tmp = 0;
      tmp += query(d,500000/d);
      res += tmp * mu[d];
   }return res;
}

void oper(int x,int val){
   for(int i=0;i<E[x].size();i++){
      int d = E[x][i];
      add(d,x/d,val);
   }
}


int A[N];
bool has[N];
int main()
{
   init();
   int n,q,x;
   scanf("%d%d",&n,&q);
   for(int i=1;i<=n;i++){
      scanf("%d",&A[i]);
   }long long ans = 0;
   while(q--){
      scanf("%d",&x);
      long long num = work(A[x]);
      if(!has[x]){
         ans += num;
         oper(A[x],1);
      }else {
         if(A[x]==1)num--;
         ans -= num;
         oper(A[x],-1);
      }has[x] = !has[x];
      printf("%I64d\n",ans);
   }return 0;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章