[联合集训6-9] Psy 组合数学+杜教筛

显然,符合条件的数必须满足任何长度的后缀字典序必须严格大于全串。
假设一个串 T T 可以由几个相同的串s拼接而成,我们称 T T 为循环串。显然所有循环串都是不满足条件的。
那么对于非循环串,那么其所有循环表示(就是切下一个前缀拼在后面)都是互不相同的。给出一个结论:一个合法串和一个环的最小循环表示串一一对应。
先证明一个合法串一定是最小循环表示串。(以下Px表示长度为 x x 的前缀,Sx表示长度为 x x 的后缀)假设合法串不是最小循环表示串,那么设从第i位开始,即 Sni+Pi(i0) S n − i + P i ( i ≠ 0 ) 是最小循环表示串,那么我们可以得到 Sni<Pni S n − i < P n − i (矛盾)或者 Sni=Pni S n − i = P n − i 并且 Si<Pi S i < P i (也矛盾),于是得证。
再证明一个最小循环表示串一定是合法的。假设其不合法,那么必然存在一个 Si<Pi S i < P i (矛盾)或者 Si=Pi S i = P i 并且把 Pni P n − i 拼到后面能得到 Pni>Si P n − i > S i (也矛盾),得证。
那么我们设 Fn F n 表示长度为 n n 的合法串的个数,显然有:

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

其中 d|ndFd ∑ d | n d F d 是减去循环串, 1n 1 n 是因为 n n 种循环表示中只有1种合法。我们设 Gi=Fin2 G i = F i ⋅ n 2 ,问题要求的就是 ni=1Gi ∑ i = 1 n G i ,那么:

i=1nGi=i=1ni10ii=1nd|i,d<iiGdd ∑ i = 1 n G i = ∑ i = 1 n i ⋅ 10 i − ∑ i = 1 n ∑ d | i , d < i i ⋅ G d d

前一个和式是一个等比数列乘等差数列,用错位相减直接求,后一个和式换成枚举 k=id k = i d ,得到
i=1nGi=n10n+110n+119+19k=2ni=1nkGk ∑ i = 1 n G i = n ⋅ 10 n + 1 − 10 n + 1 − 1 9 + 1 9 − ∑ k = 2 n ∑ i = 1 ⌊ n k ⌋ G k

直接杜教筛即可。

代码:

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值