2019.10.25 OI-Killer的模拟赛3.鸡数
Posted hansue
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019.10.25 OI-Killer的模拟赛3.鸡数相关的知识,希望对你有一定的参考价值。
题意:
定义“鸡数”指从高位到低位单调不减的数。求$[a,b]$之间有多少个“鸡数”。$t$组询问。
$1le tle 10^5,; 1le ale ble 2^{31}-1$
分析:
数位DP。设$f[i][j]$表示长度为$i$,最高位是$j$的“鸡数”个数,那么$$f[i][j]=sumlimits^9_{k=j}f[i-1][k]$$
且$$f[1][i]=1;(1le ile 9)$$
那么对于一个长度为$l$的$n$且由低到高位写成$s_{1dots l}$,$[1,n)$的答案可以分成这么几个部分:
1.长度小于$l$的所有$f$
2.长度为$iin [1,l)$中,最高位是$xin [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 ",calc(b+1)-calc(a)); } return 0; }
小结:
数位DP大同小异,推出通式,分割每位的答案再加起来。
以上是关于2019.10.25 OI-Killer的模拟赛3.鸡数的主要内容,如果未能解决你的问题,请参考以下文章