ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

         有一位售票员给乘客售票,对于每位乘客,他会卖出多张连续的票,直到已卖出的编号的所有位置上的数的和不小于给定的正数k。然后他会按照相同的规则给下一位乘客售票。初始时,售票员持有的编号是从L到R的连续整数。请你求出,售票员可以售票给多少位乘客。

Input

         三个整数L,R,k。

Output

         一个正整数,表示能够拿到票的乘客数。
f[a][b][c]表示开头的和为b,末尾在[0,10a)的数,前面补上和为c的一段数字,能分出的段数和剩余的和
预处理a=0..19,b=0..190,c=0..k-1的答案
然后类似zkw线段树查出区间[l,r]对应的信息,合并答案
#include<cstdio>
typedef long long i64;
i64 l,r,p10[20];
struct state{
    i64 c;
    int r;
    void operator+=(state w){
        c+=w.c;
        r=w.r;
    }
}f[21][197][1007];
struct pos{
    int a,b;
}stk1[10007],stk2[10007];
int stp1=0,stp2=0;
int p1=0,p2=0;
int k,sl[20],pl=0,sr[20],pr=0;
int main(){
    scanf("%lld%lld%d",&l,&r,&k);
    p10[0]=1;
    for(int i=1;i<=19;++i)p10[i]=p10[i-1]*10;
    for(int j=0;j<=190;++j){
        for(int a=0;a<k;++a){
            f[0][j][a]=(state){a+j>=k,a+j>=k?0:a+j};
        }
    }
    for(int i=1;i<=19;++i){
        for(int j=0;j<=190-i*9;++j){
            for(int a=0;a<k;++a){
                state&w=f[i][j][a]=f[i-1][j][a];
                for(int b=1;b<10;++b){
                    w+=f[i-1][j+b][w.r];
                }
            }
        }
    }
    --l;++r;
    while(l)sl[++pl]=l%10,l/=10;
    while(r)sr[++pr]=r%10,r/=10;
    pl=pr;
    int eq=pr;
    while(sl[eq]==sr[eq])--eq;
    int cl=0,cr=0;
    for(int i=1;i<=pr;++i)cl+=sl[i],cr+=sr[i];
    for(int i=1;i<eq;++i){
        cl-=sl[i],cr-=sr[i];
        for(int a=sl[i]+1;a<=9;++a)stk1[stp1++]=(pos){i-1,cl+a};
        for(int a=sr[i]-1;a>=0;--a)stk2[stp2++]=(pos){i-1,cr+a};
    }
    cr-=sr[eq];
    for(int a=sl[eq]+1;a<sr[eq];++a)stk1[stp1++]=(pos){eq-1,cr+a};
    while(stp2)stk1[stp1++]=stk2[--stp2];
    state w=(state){0,0};
    for(int i=0;i<stp1;++i)w+=f[stk1[i].a][stk1[i].b][w.r];
    printf("%lld\n",w.c);
    return 0;
}

 

posted on 2017-04-14 09:26  nul  阅读(255)  评论(0编辑  收藏  举报