4833: [Lydsy2017年4月月賽]最小公倍佩爾數

4833: [Lydsy2017年4月月賽]最小公倍佩爾數

Time Limit: 8 Sec Memory Limit: 128 MB
Submit: 119 Solved: 55
[Submit][Status][Discuss]
Description

令(1+sqrt(2))^n=e(n)+f(n)*sqrt(2),其中e(n),f(n)都是整數,顯然有(1-sqrt(2))^n=e(n)-f(n)*sqrt(2)。令g(

n)表示f(1),f(2)…f(n)的最小公倍數,給定兩個正整數n和p,其中p是質數,並且保證f(1),f(2)…f(n)在模p意義
下均不爲0,請計算sigma(i*g(i)),1<=i<=n.其在模p的值。
Input

第一行包含一個正整數 T ,表示有 T 組數據,滿足 T≤210 。接下來是測試數據。每組測試數據只佔一行,包含
兩個正整數 n 和 p ,滿足 1≤n≤10^6,2≤p≤10^9+7 。保證所有測試數據的 n 之和不超過 3×10^6 。
Output

對於每組測試數據,輸出一行一個非負整數,表示這組數據的答案。

Sample Input

5

1 233

2 233

3 233

4 233

5 233
Sample Output

1

5

35

42

121
HINT

Source

鳴謝Tangjz提供試題

[Submit][Status][Discuss]

這感覺是道非常非常難的數學題。。。
以下爲了方便,記(a,b)=gcd(a,b)[a,b]=lcm(a,b)
好像數學上也是這樣表示的?
不管怎麼樣先打個表,
發現f(1)=1,f(2)=2,f(n)=2f(n1)+f(n2)
既然f 函數這麼有規律,那麼g 呢。。。。好吧死活沒有
於是就去翻譯題解了。。。。。。題解真難!
先是把遞推式的轉移矩陣列出來,然後手算幾項
發現有規律f(n+m)=f(n1)f(m)+f(n)f(m+1)
然後大力數學歸納一下。。。發現是能證明的。。
於是(f(n+m),f(n))=(f(n1)f(m),f(n))
由打出來的表不難發現,f(n1)f(n) 是互質的
所以(f(n1)f(m),f(n))=(f(m),f(n))
顯然把互質部分的因子去掉等式仍然成立
考慮輾轉相除法的過程,可以證明(f(n),f(m))=f((n,m))
考慮任意兩個位置a,b[f(a),f(b)]=f(a)f(b)(f(a),f(b))=f(a)f(b)f((a,b))
考慮這個式子([a1,a2,,an],b)
可以只關心每類素因子對答案的貢獻
於是原式可化爲[(a1,b),(a2,b),,(an,b)]
考慮任意三個位置i,j,k
[f(i),f(j),f(k)]=[f(i),f(j)]f(k)([f(i),f(j)],f(k))=f(i)f(j)f((i,j))f(k)[f((i,k)),f((j,k))]
下面那個lcm 暴力展開就得到f(i)f(j)f(k)f((i,j,k))f((i,j))f((i,k))f((k,j))
於是乎大膽猜結論???(一輩子猜不出來系列)


上面是小清新與現實的分割線
Sn={1,2,,n}
g(n)=TSf(gcdiT(i))(1)|T|+1
這東西。。。聽說可以歸納(這個部分苟蒻親身寫了式子。。然後吐了)
那就假裝是可以用歸納法證明的吧!(皆大歡喜:D)
再定義f(n)=d|nh(d)
於是原式又化爲TSd|gcdiT(i)h(d)(1)|T|+1
這個式子。。。題解化到結果的操作姿勢太玄學。。完全看不懂
結果竟是g(n)=ni=1h(i)
h(n)=d|nf(d)u(nd)
這個用類似證明莫比烏斯反演的證明方式證明
反正剩下就是大力調和級數篩篩篩。。。
複雜度O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 1E6 + 5;

int n,p,T,tot,f[maxn],g[maxn],h[maxn],mu[maxn],pri[maxn];
bool not_pri[maxn];

#define Mul(a,b) (1LL * (a) * (b) % p)
#define Add(a,b) ((a) + (b) < p ? (a) + (b) : (a) + (b) - p)

inline int ksm(int x)
{
    int ret = 1;
    for (int y = p - 2; y; y >>= 1)
    {
        if (y & 1) ret = Mul(ret,x);
        x = Mul(x,x);
    }
    return ret;
}

void Solve()
{
    scanf("%d%d",&n,&p);
    f[1] = h[1] = g[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        f[i] = Add(Mul(2,f[i - 1]),f[i - 2]);
        g[i] = ksm(f[i]); h[i] = 1;
    }
    for (int i = 1; i <= n; i++)
    {
        if (mu[i] == 1)
        {
            for (int j = i,now = 1; j <= n; j += i,now++)
                h[j] = Mul(h[j],f[now]);
        }
        else if (mu[i] == -1)
        {
            for (int j = i,now = 1; j <= n; j += i,now++)
                h[j] = Mul(h[j],g[now]);
        }
    }
    int Ans = 0,tmp = 1;
    for (int i = 1; i <= n; i++)
    {
        tmp = Mul(tmp,h[i]);
        Ans = Add(Ans,Mul(i,tmp));
    }
    cout << Add(Ans,p) << endl;
}

int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif

    mu[1] = 1;
    for (int i = 2; i < maxn; i++)
    {
        if (!not_pri[i])
            pri[++tot] = i,mu[i] = -1;
        for (int j = 1; j <= tot; j++)
        {
            int Nex = i * pri[j];
            if (Nex >= maxn) break;
            not_pri[Nex] = 1;
            if (i % pri[j] == 0)
            {
                mu[Nex] = 0; break;
            }
            mu[Nex] = -mu[i];
        }
    }
    cin >> T; while (T--) Solve();
    return 0;
}

發佈了730 篇原創文章 · 獲贊 20 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章