【JZOJ4799】我的快乐时代

Description

这里写图片描述
原题为51Nod卷积和

Solution

设第一天到第 i 天的答案为solve(i),那么第 l 天到第r天答案可以分解为: solve(r)solve(l1)

然后我们现在要解决 Solve(n)

n 是个m位数。

假设m=5,我们可以先快速求出1~9,10~99,100~999,1000~9999的卷积和。

那么怎么计算呢?

我们知道,1~9就是1 2 +2 2 +…+9 2 =285。

10~99自己算。

对于长度为L(L>2)的,我们假设在开头结尾算,那么卷积和为:
10L29i=1i9i=0i+9(9i=0i)210L3 (想想看为什么)

那么对于长度为m的,例如有一个数 abcde¯¯¯¯¯¯¯¯

我们就分开处理,先处理 10000 (a1)9999¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ,再处理 a0000¯¯¯¯¯¯¯¯¯ a(c1)999¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ……

至于计算的方法,其实和前面的差不多,只是要固定一些数字。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define ll long long
#define mo 1000000007
#define N 20
using namespace std;
ll qz[30]={0,1,3,6,10,15,21,28,36,45,0,1,2,3,4,5,6,7,8,9};
ll pf[30]={0,1,5,14,30,55,91,140,204,285,0,1,4,9,16,25,36,49,64,81};
ll z[N];
int q[N];
void get(ll x)
{
    q[0]=0;
    if(!x) q[0]=1,q[1]=0;
    while(x) q[++q[0]]=x%10,x/=10;
}
int fw[N],ct[N];
ll calc(ll n)
{
    if(n<1) return 0;
    ll ans=0;
    get(n);
    fo(i,1,q[0]-1)
    {
        if(i==1)
        {
            ans=(ans+285)%mo;
            continue;
        }
        else if(i==2)
        {
            ans=(ans+4050)%mo;
            continue;
        }
        ans=(ans+4050*z[i-2]%mo+4050*9%mo*z[i-3]%mo*(i/2-1)%mo)%mo;
        if(i%2==1) ans=(ans+285*9%mo*z[i-2]%mo)%mo;
    }
    fd(i,q[0],1)
    {
        ct[i]=10;
        fw[i]=9;
    }
    if(q[0]==1) ans=(ans+pf[q[1]]%mo)%mo;
    else if(q[0]==2) ans=(ans+qz[q[2]-1]*45*2%mo+q[2]*qz[q[1]]*2%mo)%mo;
    else
    fd(i,q[0],1)
    {
        ct[i]=q[i]-1;
        if(i!=q[0]) ct[i]++;
        fw[i]=q[i]-1;
        if(i==1) fw[i]++,ct[i]++;
        int p=q[0]/2;
        fo(j,1,p)
        {
            int k=q[0]-j+1;
            ll tmp=0;
            if(j==1) tmp=(tmp+qz[fw[j]]*qz[fw[k]]%mo*2%mo)%mo;
            else tmp=(tmp+qz[fw[j]]*qz[fw[k]]%mo*2%mo)%mo;
            fo(l,1,q[0])
            if(l!=j && l!=k) tmp=tmp*ct[l]%mo;
            ans=(ans+tmp)%mo;
        }
        if(q[0]%2==1)
        {
            p++;
            ll tmp=0;
            tmp=pf[fw[p]];
            fo(j,1,q[0])
            if(j!=p) tmp=tmp*ct[j]%mo;
            ans=(ans+tmp)%mo;
        }
        fw[i]=q[i]+10;
        ct[i]=1;
    }
    return ans;
}
int main()
{ 
    z[0]=1;
    fo(i,1,N-1) z[i]=z[i-1]*10%mo;
    ll l,r;
    cin>>l>>r;
    cout<<(calc(r)-calc(l-1)+mo)%mo;
}
posted @ 2016-09-28 20:39  sadstone  阅读(46)  评论(0编辑  收藏  举报