码迷,mamicode.com
首页 > 其他好文 > 详细

【2019.10.25 OI-Killer的模拟赛】3.鸡数

时间:2019-10-25 23:12:55      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:open   code   多少   iostream   sig   play   unsigned   https   register   

题目链接

 

题意:

  定义“鸡数”指从高位到低位单调不减的数。求$[a,b]$之间有多少个“鸡数”。$t$组询问。

  $1\le t\le 10^5,\; 1\le a\le b\le 2^{31}-1$

 

分析:

  数位DP。设$f[i][j]$表示长度为$i$,最高位是$j$的“鸡数”个数,那么$$f[i][j]=\sum\limits^9_{k=j}f[i-1][k]$$

  且$$f[1][i]=1\;(1\le i\le 9)$$

  那么对于一个长度为$l$的$n$且由低到高位写成$s_{1\dots l}$,$[1,n)$的答案可以分成这么几个部分:

  1.长度小于$l$的所有$f$

  2.长度为$i\in [1,l)$中,最高位是$x\in [s_{i+1},s_i)$的$f$

 

实现(100分):

 

技术图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#define IL inline
#define UI unsigned int
#define RI register int
#define _1 first
#define _2 second
using namespace std;
const int N=10;
const int M=9;

    int f[N+3][M+3];
    int g[N+3],h[N+3];
    
    int k,s[N+3];
IL int calc(int x){
    k=0;
    while(x>0){
        s[++k]=x%10;    x/=10;
    }
    
    int ret=h[k-1];
    s[k+1]=0;
    for(int i=k;i>0&&s[i]>=s[i+1];i--)
        for(int j=s[i+1];j<s[i];j++)
            ret+=f[i][j];
    return ret;
    
}

    int T,a,b;

int main(){
    memset(f,0,sizeof f);
    memset(g,0,sizeof g);
    memset(h,0,sizeof h);
    for(int i=1;i<=M;i++)
        f[1][i]=1;
    g[1]=h[1]=M;
    for(int i=2;i<=N;i++){
        for(int j=1;j<=M;j++){
            for(int k=j;k<=M;k++)
                f[i][j]+=f[i-1][k];
            g[i]+=f[i][j];
        }
        h[i]=h[i-1]+g[i];
    }

    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&a,&b);
        printf("%d\n",calc(b+1)-calc(a));
        
    }

    return 0;

}
View Code

 

 

小结:

  数位DP大同小异,推出通式,分割每位的答案再加起来。

【2019.10.25 OI-Killer的模拟赛】3.鸡数

标签:open   code   多少   iostream   sig   play   unsigned   https   register   

原文地址:https://www.cnblogs.com/Hansue/p/11740315.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!