1. 程式人生 > >2017第二次多校聯合hdu6053Tirck Gcd

2017第二次多校聯合hdu6053Tirck Gcd

假裝這裡有連結

題意:給出A的序列,然後根據A的序列去確定B的序列。
B的序列滿足1BiAi且對於任意B的子集的gcd2.

解:首先考慮任意B的子集的gcd2這個條件。它代表的含義即B中任意兩個數不互質。那個B中的數都是倍數關係。然後再來看A,已知了A序列,那我們可以列舉小於A但是大於1的所有數。拿樣例來看,A的序列為4 4 4 4,然後從2開始列舉,列舉到2的時候,2是4的因子,且44,所以這時候不論是取2還是取4都是可以的,所以是4*C(12),然後列舉到3,只有這一種情況,然後到4,也是一種情況,但是在列舉2的時候已經考慮的2的倍數4的情況了,所以重複去掉,答案是16+4=17.
經過簡單的推導,我們可以推出含重複答案的公式為:

aminx=2(ni=1a[i]x)
下面我們開始討論重複的答案如何去重。應用簡單的容斥原理,就是下面的那張圖,然後用篩法求莫比烏斯函式實現。
|A∪B∪C|=|A|+|B|+|C|−|A∩B|−|B∩C|−|A∩C|+|A∩B∩C|
這裡寫圖片描述

但是從對每個可能的Bi都列舉一遍A,這樣是n2的時間複雜度對於105的資料來說是絕對會超時的,所以需要優化。
仔細觀察可以得知,在某個範圍裡的數對於一個固定的Bi所對應的種數是一樣的。比如對於5來說,1-4裡面有0個5,5-9裡面有5個5,10-14裡面有2個5……………..
所以我們就可以將這一個整塊的資料同時處理,這樣就會節約很多時間。

#include<bits/stdc++.h>
using namespace std; const int maxn=1e5+5; const int mod=1e9+7; #define ll long long ll m[100010]; void mu() { m[1]=1; for(ll i=1; i<=maxn; i++) for(ll j=2*i; j<=maxn; j+=i) { m[j]-=m[i]; } } ll a[maxn],num[2*maxn]; ll qmod(ll a,ll b) { ll ans=1; while
(b) { if(b%2==1)ans=ans*a%mod; a=(a*a)%mod; b/=2; } return ans; } int main() { ll minx,t,ca=1; mu(); scanf("%lld",&t); while(t--) { memset(a,0,sizeof a); memset(num,0,sizeof num); ll n; scanf("%lld",&n); minx=maxn+10; for(int i=1; i<=n; i++) { scanf("%d",&a[i]); minx=min(a[i],minx); } for(int i=1; i<=n; i++) { num[a[i]]++; } for(int i=1; i<=200000; i++) { num[i]+=num[i-1]; } ll ans=0; for(ll i=2; i<=minx; i++) { ll sum=1; for(ll j=1; j*i<=100000; j++) { sum=(sum*qmod(j,num[(j+1)*i-1]-num[j*i-1]))%mod; //j代表優化中拿的種數 } ans=(ans-sum*m[i]%mod+mod)%mod; } printf("Case #%lld: %lld\n",ca++,ans); } }