洛谷 P3307 [SDOI2013]項鍊 burnside引理+polya定理+莫比烏斯反演
題目描述 項鍊是人體的裝飾品之一,是最早出現的首飾。項鍊除了具有裝飾功能之外,有些項 鏈還具有特殊顯示作用,如天主教徒的十字架鏈和佛教徒的念珠。
從古至今人們為了美化人體本身,也美 化環境,製造了各種不同風格,不同特點、不同式樣的項鍊,滿足了不同膚色、不同民族、不同審美觀的人的審美需要。就材料而論,首飾市場上的項鍊有黃金、白銀、珠寶等幾種。
珍珠項鍊為珍珠製成的飾品,即將珍珠 鑽孔後用線串在一起,佩戴於項間。天然珍珠項鍊具有一定的護養作用。 最近,銘銘迷戀上了一種項鍊。與其他珍珠項鍊基本上相同,不過這種項鍊的珠子卻 與眾不同,是正三菱柱的泰山石雕刻而成的。
三菱柱的側面是正方形構成的,上面刻有數字。 能夠讓銘銘滿意的項鍊必須滿足下面的條件:
1:這串項鍊由n顆珠子構成的。
2:每一個珠子上面的數字x,必須滿足0<x<=a,且珠子上面的數字的最大公約數要恰 好為1。兩個珠子被認為是相同的,當且僅當他們經過旋轉,或者翻轉後能夠變成一樣的。
3:相鄰的兩個珠子必須不同。
4:兩串項鍊如果能夠經過旋轉變成一樣的,那麼這兩串項鍊就是相同的! 銘銘很好奇如果給定n和a,能夠找到多少不同串項鍊。由於答案可能很大,所以對輸 出的答案mod 1000000007。
輸入輸出格式
輸入格式: 資料由多組資料構成: 第一行給定一個T<=10,代表由T組資料。 接下來T行,每行兩個數n和a。
輸出格式: 對於每組資料輸出有多少不同的串。
輸入輸出樣例
輸入樣例#1: 1 2 2 輸出樣例#1: 3 說明
對於100%的資料:所有的n<=1014,a<=107,T<=10;
樣例解釋:由三種珠子:[1,1,1],[1,1,2],[1,2,2].組成的串有:[1,2],[1,3],[2,3]。
分析: 我們先求出不同的珠子有多少個。相當於求有序三元組使得。 我們考慮化成無序三元組。對於任意一個無序時會被算6次。而當有時,少算三次。當時,此時,這個少算5次,但是有3次已經在算過,所欲只要加2次。 即,設為無序三元組答案,為無序二元組方案,那麼不同珠子數。
考慮求和,很套路的莫比烏斯反演一下就得到
考慮能拼出多少個項鍊。 可以考慮用burnside引理+polya定理。顯然置換有個。分別是,,… 考慮迴圈,假設第個置換是對的那個,顯然迴圈有個,又因為這些迴圈是相連的,而迴圈中的取值相同。 我們設為一個大小為的環,相鄰兩個顏色都不同的方案。那麼第個置換的答案就是。 也就是。 我們設,則 然後也就是。 而 可以理解為在個環的任意一個位置,由於兩邊顏色不同,可以取種;或者在個環中放一個顏色相同的,再在兩個相同顏色中放一個顏色不同的,有種情況。可以矩陣乘搞。
還有就是有可能是的倍數,所以上述運算要在意義下跑。如果不是倍數,那麼直接把算出來的答案模再乘逆元;否則把結果先除n,然後乘在意義下的值。
程式碼:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const LL p=1e9+7;
const LL mod=p*p;
const int maxn=1e7+7;
const LL inv6=833333345000000041;
using namespace std;
int T;
LL n,m,cnt,k,ans,num;
LL prime[maxn],mu[maxn],q[10007],a[10007];
bool not_prime[maxn];
LL mul(LL x,LL y)
{
LL tmp=x*y-(LL)((long double)x*y/mod+0.1)*mod;
if (tmp<0) tmp+=mod;
return tmp;
}
void getmu(LL n)
{
mu[1]=1;
for (LL i=2;i<=n;i++)
{
if (!not_prime[i])
{
prime[++cnt]=i;
mu[i]=-1;
}
for (LL j=1;j<=cnt;j++)
{
if (i*prime[j]>n) break;
not_prime[i*prime[j]]=1;
if (i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else mu[i*prime[j]]=-mu[i];
}
}
for (LL i=1;i<=n;i++) mu[i]+=mu[i-1];
}
LL power(LL x,LL y)
{
if (!y) return 1;
LL c=power(x,y/2);
c=mul(c,c);
if (y%2) c=mul(c,x);
return c;
}
LL power1(LL x,LL y)
{
if (!y) return 1;
LL c=power1(x,y/2);
c=(c*c)%p;
if (y%2) c=(c*x)%p;
return c;
}
void calc()
{
LL s1=0,s2=0;
for (int i=1,last;i<=m;i=last+1)
{
last=m/(m/i);
s1=(s1+mul(power(m/i,3),(mu[last]+mod-mu[i-1])%mod))%mod;
s2=(s2+mul(power(m/i,2),(mu[last]+mod-mu[i-1])%mod))%mod;
}
k=mul(inv6,((s1+mul(s2,3)+2)%mod));
}
LL F(LL x)
{
LL tmp=power(k-1,x);
if (x&1) tmp=(tmp+1+mod-k)%mod;
else tmp=(tmp+k-1)%mod;
return tmp;
}
void dfs(LL x,LL d,LL phi)
{
if (x>num)
{
ans=(ans+mul(phi,F(n/d)))%mod;
return;
}
dfs(x+1,d,phi);
int s=1;
for (int i=1;i<=q[x];i++)
{
d*=a[x];
phi*=a[x]-s;
s=0;
dfs(x+1,d,phi);
}
}
int main()
{
scanf("%d",&T);
getmu(1e7);
while (T--)
{
scanf("%lld%lld",&n,&m);
calc();
LL x=n;
num=0;
for (int i=1;i<=cnt&&(prime[i]*prime[i]<=n);i++)
{
if (x%prime[i]==0)
{
a[++num]=prime[i];
q[num]=0;
while (x%prime[i]==0) q[num]++,x/=prime[i];
}
}
if (x) a[++num]=x,q[num]=1;
ans=0;
dfs(1,1,1);
if (n%p==0) ans=(ans/p)*power1(n/p,p-2)%p;
else ans=(ans%p)*power1(n%p,p-2)%p;
printf("%lld\n",ans);
}
}