NOIP模擬 gcd 數學

題面不給……題意:動態增減集合中元素個數,動態求$gcd(i,j)==1$的數的個數。ios

坦白地講題解並沒徹底看懂……因而聽$lc$開了一會車(快開完時$xyz$強行砸場致使爛尾),結合着本身理解又推一遍想明白了……ide

在本題之中,咱們設$f(x)$爲$gcd(i,j)==x$的數的個數,$g(x)$爲$gcd(i,j)==kx$的數的個數。很顯然$f(x)=g(x)-f(2x)-f(3x)...$,這樣推下去,咱們就會發現這個係數實際上是符合莫比烏斯函數的,最後大力化簡就是:函數

\[ \sum_{d}^{} {μ(d)*g(d)} =f(d)\]。spa

如今定義$s(i)$爲當前選中的集合中爲$i$倍數數的個數,能夠看出,$g(i)=s(i)*(s(i)-1)/2$。3d

而後咱們就能夠預處理莫比烏斯函數,在每一次修改元素個數時候動態維護$s(i)$。code

可是咱們暴力求$ans$顯然會$T$……因而考慮每一次加入或刪除元素對於最後結果貢獻。blog

當咱們插入一個元素,對於每個能夠整除它的$i$,$Δans=μ(i)*((s(i)+1)*s(i)-s(i)*(s(i)-1))/2=μ(i)s(i)$。同理,刪除時,對於每個這樣的$i$,$Δans=μ(i)*((s(i)-2)*(s(i)-1)-s(i)*(s(i)-1))/2=-μ(i)(s(i)-1)$。而後咱們根據這個規律轉移便可。string

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn=200005,maxx=500005;
 7 bool notprime[maxx];int prime[maxx],cnt,mu[maxx];
 8 void init()
 9 {
10     mu[1]=1;
11     for(int i=2;i<=500000;i++)
12     {
13         if(!notprime[i])prime[++cnt]=i,mu[i]=-1;
14         for(int j=1;j<=cnt&&i*prime[j]<=500000;j++)
15         {
16             notprime[i*prime[j]]=1;
17             if(i%prime[j])mu[i*prime[j]]=-mu[i];
18             else {mu[i*prime[j]]=0;break;}
19         }
20     }
21 }
22 int n,m,a[maxn],s[maxx],maxv,t[maxn];
23 int haha()
24 {
25     scanf("%d%d",&n,&m);init();
26     for(int i=1;i<=n;i++)scanf("%d",&a[i]),maxv=max(maxv,a[i]);
27     long long ans=0;
28     for(int i=1;i<=m;i++)
29     {
30         int x;scanf("%d",&x);int sgn=t[x]?-1:1;
31         for(int j=1;j*j<=a[x];j++)
32             if(!(a[x]%j))
33             {
34                 if(sgn==1)ans+=1ll*mu[j]*s[j];else ans-=1ll*(s[j]-1)*mu[j];s[j]+=sgn*1;
35                 if(j*j<a[x])
36                 {
37                     if(sgn==1)ans+=1ll*mu[a[x]/j]*s[a[x]/j];else ans-=1ll*(s[a[x]/j]-1)*mu[a[x]/j];
38                     s[a[x]/j]+=sgn*1;
39                 }
40             }
41         t[x]^=1;
42         printf("%lld\n",ans);
43     }
44 }
45 int sb=haha();
46 int main(){;}
C
相關文章
相關標籤/搜索