NOIP提高组【JZOJ4799.】我的快乐时代

9 篇文章 0 订阅

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

这道题我们考虑一下类似数位dp的东西,答案=1~r的答案-1~l-1的答案,于是我们分开出答案,这里只举l-1的例子。我们枚举位数。

1、显然,在位数l-1的长度>k的时候,对于每两对 di,dki+1 ,他们出现在1~l-1中的数量显然为 910k3 (因为第一位不能为0),特别的,当i=1时数量就为 10k2 。我们还要考虑一下当位数k为奇数的时候,那么显然中间的那个会出现( dk/2dk/2 )的情况,这时的数量就为 910k2 。最后枚举一下这两个 di,dki+1 分别是什么,记录一下贡献即可。

2、在位数k=l-1的长度的时候,对于每两对 di,dki+1 ,这时要考虑的情况就比较多了。我们枚举前x位与l-1的前x位相等,那么剩下的数量显然就是 lx+110lenlx1+1 ,最后枚举一下这两个 di,dki+1 分别是什么,记录一下贡献即可。

代码

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=1000000007;
ll l,r,i,t,j,k,len1,len2,x,y,f[20],ans1,ans2,a[20],b[20],c[20],d[20],l1,r1;
int dg(ll len1){
    ll i,j,t,k,l,x,y,ans1=0;
    for (i=1;i<len1;i++){
        t=i/2;
        for (j=2;j<=t;j++)
            for (k=1;k<=9;k++)
                for (l=1;l<=9;l++) ans1=(ans1+f[i-3]*k*l*18%maxn)%maxn;
        if (i!=1){
            for (k=1;k<=9;k++)
                for (l=1;l<=9;l++)ans1=(ans1+f[i-2]*k*l*2%maxn)%maxn;
        }
        if (!(i%2))continue;
        if (i!=1){
            for (k=1;k<=9;k++)
                ans1=(ans1+f[i-2]*9*k*k%maxn)%maxn;
        }else ans1=285;
    }
    t=len1/2;
    for (j=1;j<=t;j++)
        for (k=1;k<=9;k++)
            for (l=1;l<=9;l++){
                if (j==1 && l>a[len1-j+1]) break;
                ans1=(ans1+c[len1-j+1]*k*l%maxn*f[len1-j-1]%maxn*2%maxn)%maxn;
                if (l>a[len1-j+1]) continue;
                if (l<a[len1-j+1]) ans1=(ans1+k*l*f[len1-j-1]*2%maxn)%maxn;
                if (l==a[len1-j+1]){
                    for (x=len1-j;x>j;x--)
                        ans1=(ans1+k*l*f[x-2]*a[x]*2%maxn)%maxn;
                    if (k<a[j]) ans1=(ans1+k*l*f[j-1]*2%maxn)%maxn;
                    if (k==a[j]){
                        for (x=j-1;x>0;x--)
                            ans1=(ans1+k*l*f[x-1]*a[x]*2%maxn)%maxn;
                        ans1=(ans1+k*l*2)%maxn;
                    }
                }

            }
    if (len1%2){
        if (len1==1){
            for (i=1;i<=a[1];i++)
                ans1+=i*i;
            return ans1;
        }
        t++;
        for (k=1;k<=9;k++){
            l=k;
            ans1=(ans1+c[t]*k%maxn*k%maxn*f[t-1]%maxn)%maxn;
            if (l>a[t]) continue;
            if (l<a[t]) ans1=(ans1+k*k*f[t-1]%maxn)%maxn;
            if (l==a[t]){
                for (x=t-1;x>0;x--)
                    ans1=(ans1+k*k*f[x-1]*a[x]%maxn)%maxn;
                ans1=(ans1+k*k%maxn)%maxn;
            }
        }
    }
    return ans1;
}
int main(){
//  freopen("data.in","r",stdin);
    scanf("%lld%lld",&l1,&r1);l1--;
    t=l1;
    f[0]=1;
    for (i=1;i<=18;i++)
        f[i]=f[i-1]*10;
    while (t)a[++len1]=t%10,t=t/10;
    for (i=1;i<len1;i++)
        c[i]=(l1/f[i]-f[len1-i-1])%maxn;
    t=r1;
    while (t)b[++len2]=t%10,t=t/10;
    for (i=1;i<len2;i++){
        t=r1/f[i];
        d[i]=(t-f[len2-i-1])%maxn;
    }
    for (i=1;i<=18;i++)
        f[i]=f[i]%maxn;
    ans1=dg(len1);
    for (i=0;i<=len2;i++)
        c[i]=d[i],a[i]=b[i];
    ans2=dg(len2);
    ans2=(ans2+maxn-ans1)%maxn;
    printf("%d\n",ans2);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值