[聯合集訓6-9] Psy 組合數學+杜教篩

顯然,符合條件的數必須滿足任何長度的後綴字典序必須嚴格大於全串。
假設一個串T 可以由幾個相同的串s 拼接而成,我們稱T 爲循環串。顯然所有循環串都是不滿足條件的。
那麼對於非循環串,那麼其所有循環表示(就是切下一個前綴拼在後面)都是互不相同的。給出一個結論:一個合法串和一個環的最小循環表示串一一對應。
先證明一個合法串一定是最小循環表示串。(以下Px 表示長度爲x 的前綴,Sx 表示長度爲x 的後綴)假設合法串不是最小循環表示串,那麼設從第i 位開始,即Sni+Pi(i0) 是最小循環表示串,那麼我們可以得到Sni<Pni (矛盾)或者Sni=Pni 並且Si<Pi (也矛盾),於是得證。
再證明一個最小循環表示串一定是合法的。假設其不合法,那麼必然存在一個Si<Pi (矛盾)或者Si=Pi 並且把Pni 拼到後面能得到Pni>Si (也矛盾),得證。
那麼我們設Fn 表示長度爲n 的合法串的個數,顯然有:

Fn=1n(10nd|n,d<ndFd)

其中d|ndFd 是減去循環串,1n 是因爲n 種循環表示中只有1 種合法。我們設Gi=Fin2 ,問題要求的就是i=1nGi ,那麼:
i=1nGi=i=1ni10ii=1nd|i,d<iiGdd

前一個和式是一個等比數列乘等差數列,用錯位相減直接求,後一個和式換成枚舉k=id ,得到
i=1nGi=n10n+110n+119+19k=2ni=1nkGk

直接杜教篩即可。

代碼:

include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int mod=1000000007;
const int R=100000;
const int T=3000000;
ll n,i9,i2;
int mg[R+5],g[T+5];
ll ksm(ll a,ll b)
{
    ll r=1;
    for(;b;b>>=1,a=a*a%mod)
        if(b&1) r=r*a%mod;
    return r;   
}
ll solve(ll x)
{
    ll m=n/x,pp,ans;
    if(m<T) return g[m];x=n/m;
    if(x<R&&mg[x]>=0) return mg[x];
    pp=ksm(10,m+1);
    ans=(pp*(m-i9+mod)+i9+1)%mod*i9%mod;
    for(ll l=2,r;l<=m;l=r+1)
    {
        r=m/(m/l);
        ll s=((l+r)%mod)*((r-l+1)%mod)%mod*i2%mod;
        ans=(ans-s*solve(x*l)%mod+mod)%mod;
    }  
    if(x<R) mg[x]=ans;
    return ans;
}

int main()
{
    scanf("%lld",&n);
    memset(mg,-1,sizeof(mg));
    i9=ksm(9,mod-2);
    i2=ksm(2,mod-2);
    g[1]=10;
    for(int i=2;i<=T;i++)
        g[i]=10ll*g[i-1]%mod;
    for(int i=1;i<=T;i++)
    {
        for(int j=(i<<1);j<=T;j+=i)
            g[j]=(g[j]+mod-g[i])%mod;
        g[i]=((ll)g[i]*i+g[i-1])%mod;
    }       
    printf("%lld",solve(1));
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章