【NOIP模拟】我的快乐时代

64 篇文章 0 订阅
45 篇文章 0 订阅

Description

这里写图片描述

Solution

分类细节太多了,比赛时搞不出来。
很容易想到用r的答案减去l-1的答案。
然后也很容易想到枚举两个位置i和j来计算,其余位置出现的数的情况。
计算出现的数的情况有两种方法,一个是数位DP(比较好打),另一个是直接算。
我打的是直接算,搞了我好久。
首先先把奇数串中间的自己成自己的情况给搞出来。
假如i是奇数串的中间那个,那么串的长度就是2*i-1,那么分三种情况:
1、2*i-1>最大长度——break
2、2*i-1<最大长度——然后又分两种情况,i=1:答案就上285(1*1+2*2+…+9*9);否则,第一位填9,除了第i位其余填10然后乘上285。
3、2*i-1=最大长度——首先从第一位到i+1为一个个让它达到满的,然后边弄边算。然后在第i位时,再分一个满和不满的情况就好了。
然后下面要处理两个数的情况,也像上面一样做就好了,不过上面是1~i和i+1~n两段,这里是三段。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int mo=1000000007;
typedef long long ll;
ll i,j,k,l,t,n,m,ans,yi,er,len,da;
ll f[20],shi[20],jiu[20];
bool bz;  
ll suan(int l,int r,int bz){
    ll i,j,k=0,y=l+r-1;
    if(!bz){
        if(l==1)return 2*shi[y-2]*2025%mo;
        else return shi[y-3]*9*2025*2%mo;
    }
    else{
        fod(i,y,r+1)k=(k+(f[i]-(i==y))*2025*shi[i-3]%mo)%mo;
        fo(i,1,f[r]-1)k=(k+shi[r-2]*i*45%mo)%mo;
        fod(i,r-1,l+1)k=(k+f[i]*shi[i-2]*(45*f[r])%mo)%mo;
        fo(i,1,f[l]-1)k=(k+shi[l-1]*f[r]*i%mo)%mo;
        k=(k+(da%shi[l-1]+1)*f[l]*f[r]%mo)%mo;
    }
    return k*2;
}
ll calc(ll x){
    ll i,j,k=0,l=x,y=0;
    da=x;
    if(x<1)return 0;
    while(l){
        ++y;
        f[y]=l%10;
        l/=10;
    }
    fo(i,1,y){
        if(i*2-1>y)break;
        else{
            if(i*2-1==y){
                fod(j,y,i+1){
                    k=(k+(f[j]-(j==y))*shi[j-2]*285%mo)%mo;
                }
                fo(j,1,f[i]-1)k=(k+j*j*shi[i-1]%mo)%mo;
                k=(k+f[i]*f[i]*(x%shi[i-1]+1)%mo)%mo;
            }
            else{
                if(i==1)k=(k+285)%mo;
                else k=(k+9*285*shi[i*2-3]%mo)%mo;
            }
        }
    }
    fo(i,1,y){
        fo(j,i+1,y){
            if(i+j-1>y)break;
            else k=(k+suan(i,j,(i+j-1==y)))%mo;
        }
    }
    return k;
}
int main(){
    scanf("%lld%lld",&n,&m);
    shi[0]=1;
    fo(i,1,18)shi[i]=shi[i-1]*10%mo;
    printf("%lld\n",((calc(m)-calc(n-1))%mo+mo)%mo);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值