2017第二次多校聯合hdu6053Tirck Gcd
阿新 • • 發佈:2018-12-24
假裝這裡有連結
題意:給出A的序列,然後根據A的序列去確定B的序列。
B的序列滿足
解:首先考慮任意B的子集的gcd
經過簡單的推導,我們可以推出含重複答案的公式為: aminx=2
下面我們開始討論重複的答案如何去重。應用簡單的容斥原理,就是下面的那張圖,然後用篩法求莫比烏斯函式實現。
|A∪B∪C|=|A|+|B|+|C|−|A∩B|−|B∩C|−|A∩C|+|A∩B∩C|
但是從對每個可能的
仔細觀察可以得知,在某個範圍裡的數對於一個固定的
所以我們就可以將這一個整塊的資料同時處理,這樣就會節約很多時間。
#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);
}
}