Mike and Foam
题目描述
题解
对于每次询问可以对新加入的数或移除的数进行单独贡献计算
假设新加入或移除的数为\(x=p_1^{\alpha_1}p_2^{\alpha_2}···p_k^{\alpha_k}\)
显然每个质数的系数无关紧要,所以对一新加入\移除的数只考虑已存在的数中是否有\(p_1,p_2,···,p_k\)
因为\(x\leq 5*10^5 <2*3*5*7*11*13*17=510510\),所以x最多有6个不同的质因子
那么如何找已存在的数中没有这些质因子的个数
可以考虑容斥原理
\(设a_i为已存在的数中能被i整除的个数\)
则新加\移除一个数x的贡献为
\(N(\prod_{i=1}^{x的质因子个数k} \:\:\:\:\:\:(1-p_i))=\sum_{i=0}^{k}(-1)^i \cdot \sum_{从x的质因子中选i个相乘为t} N(a_t)\)
每次后询问更新\(N(a_i)\)的值
总时间复杂度为\(O(2^6q)\)
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stdlib.h>
#define ll long long
using namespace std;
const int maxn=500000+10101;
const int MOD=12345678;
const int inf=2147483647;
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,q,a[maxn],br[maxn][8],book[maxn],value[maxn],ma[8];
int tot,prime[maxn],is[maxn];
void get_prime(){
for(int i=2;i<=200000;i++){
if(!is[i])prime[++tot]=i;
for(int j=1;j<=tot && prime[j]<=200000/i;j++){
is[i*prime[j]]=1;
if(!i%prime[j])break;
}
}
return ;
}
ll ans,sum;
int tt,ji[101];
void dfs(int pos,int step,int k){ //容斥
if(step>br[pos][0]){
ll s1=1;
for(int i=1;i<=br[pos][0];i++){if(ma[i])s1*=br[pos][i];}
sum=sum+k*value[s1];ji[++tt]=s1;
return ;
}
dfs(pos,step+1,k);if(br[pos][step]==1)return; //对于a_pos=1的特判
ma[step]^=1;dfs(pos,step+1,k*(-1));ma[step]^=1;
return ;
}
ll solve(int x){
int xi=1;
if(book[x])xi=-1,book[x]=0;
else book[x]=1;
memset(ma,0,sizeof(ma));sum=0;tt=0;
dfs(x,1,1);ans=ans+xi*sum;
for(int i=1;i<=tt;i++)value[ji[i]]+=xi;
if(a[x]==1 && xi==-1)ans++; //可能1会被多减一次,因为gcd(1,1)=1
return ans;
}
int main(){
n=read();q=read();get_prime();
for(int i=1;i<=n;i++){
a[i]=read();int now=a[i];
if(a[i]==1){br[i][++br[i][0]]=1;continue;}
for(int j=1;j<=tot && now>1 && prime[j]<=sqrt(now);j++){
if(now%prime[j]==0){
br[i][++br[i][0]]=prime[j];
while(now%prime[j]==0)now/=prime[j];
}
}
if(now>1)br[i][++br[i][0]]=now;
}
for(int i=1;i<=q;i++){int x=read();printf("%lld\n",solve(x));}
return 0;
}