[SCOI2009] windy 数
首先肯定是要做差的:$ans_{[l,r]}=ans_{[r,0]}-ans_{[l-1,0]}$。
现在考虑如何求出 $ans_{[n,0]}$。
定义状态 $f(i,j,k)$,表示第 $i$ 位填 $j$,从高到低的前 $i$ 为是否贴着上界的情况为 $k$(若 $k=1$ 则贴着上界,$k=0$ 则不贴着上界)。
然后我们随便转移一下。
$$f(i,a_i,1)\rightarrow \begin{cases}f(i+1,p,0) & |p-a_i|\ge 2,p<a_{i+1} \\ f(i+1,a_{i+1},1) & |a_{i+1}-a_i|\ge 2\end{cases}$$
转移的意思是,如果前 $i$ 位都贴着上界,则后面这一位不能超过上界,且如果等于上界,则前面 $i+1$ 位都是贴着上界的。与此同时,我们还要满足数字差大于等于 2 的条件。
然后还有转移:
$$\begin{matrix}f(i,j,0)\rightarrow f(i+1,p,0)&|j-p|\ge 2\end{matrix}$$
然后我们要考虑一下前导 0 的情况。
显然前导零在两位之差大于等于 2 的情况下都能正常转移,但是一旦下一位是 1 和 0 的时候就转移不过去了,所以我们单独抽出这两个状态转移。
然后就是特判 0。。。因为这个情况它一位也拆不出来,但要输出 1(因为在计算其他数的时候我们也把 0 算上了)。
初始化就是最高位的那几种取值都是数量为 1。
时间复杂度 $O(\log n)$
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
   | #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #define ll long long using namespace std; namespace Ehnaev{   inline ll read() {     ll ret=0,f=1;char ch=getchar();     while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}     while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}     return ret*f;   }   inline void write(ll x) {     static char buf[22];static ll len=-1;     if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}     else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}     while(len>=0) putchar(buf[len--]);   } }using Ehnaev::read;using Ehnaev::write; inline void writeln(ll x) {write(x);putchar(10);}
  const ll N=15;
  ll l,r; ll f[N+5][N+5][2],a[N+5];
  inline ll F(ll n) {   if(n==0) return 1;   memset(f,0,sizeof(f));   ll len=0;   while(n) {a[++len]=n%10;n/=10;}   for(ll i=0;i<a[len];i++) f[len][i][0]=1;f[len][a[len]][1]=1;   for(ll i=len;i>=2;i--) {     for(ll j=0;j<=9;j++) {       for(ll p=0;p<=9;p++) {         if(abs(j-p)>=2) {           f[i-1][p][0]+=f[i][j][0];         }       }     }     f[i-1][0][0]+=1;f[i-1][1][0]+=1;     if(abs(a[i]-a[i-1])>=2) f[i-1][a[i-1]][1]+=f[i][a[i]][1];     for(ll p=0;p<a[i-1];p++) {       if(abs(p-a[i])>=2) {         f[i-1][p][0]+=f[i][a[i]][1];       }     }   }   ll res=0;   for(ll i=0;i<=9;i++) {     res+=f[1][i][0];        }   res+=f[1][a[1]][1];      return res; }
  int main() {
    l=read();r=read();
    
    writeln(F(r)-F(l-1));
    return 0; }
   |