[联合集训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;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DOFYPXY/article/details/80686422
个人分类: 组合数学 杜教筛
上一篇[联合集训6-9] El 点分治+哈希表
下一篇[联合集训6-9]Congroo 二进制分组+凸包上二分
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭