[SCOI2009]windy数

YYY posted @ 2015年7月06日 22:06 with tags 数位DP DP , 630 阅读
_THIS_IS_START_OF_ARTICLE_
 
写完这道题感觉心好累...这辈子都不想再做数位DP的题了,然而他们说这是道入门题...
首先可以DP得到位数为i,最高位为j的windy数个数g(i,j)
然后对于(0,k)内的windy数个数,可以讨论3种情况:(感觉数位DP就是大讨论..)
(假设总位数为l,假设k的从高到低第t位为bit(t) )
①最高位为0,位数为[1,l - 1]的windy数个数(Σ(q=1,l-1) Σ(p=1,9) g(p,q))
②最高位为[1,k - 1],位数为l的windy数个数(Σ(q=1,k-1) g(l,q))
③最高位为k的windy数个数,这个比较复杂,总之是从高位到低位依次确定,伪代码如下:
for i = (len - 1) to 1 , step -1:
  for q = 1 to bit(i) - 1 (#) , step 1: 
   if(|q - bit(i + 1)| > 2)
     sum <- sum + g(i,q)
   endif
  endfor
endfor
 
注意打#的地方,这里取bit(i) - 1是因为求的是开区间(闭区间的话会麻烦一点)
 
完整代码如下:
#include <stdio.h>
#include <string.h>
#include <iostream>
 
typedef long long Long;
 
Long g[20][20];//g[i][j] : i位开头为j的windy数个数 
 
Long ABS(Long a)
{
    return a > (Long)0 ? a : -a;
}
 
void init()
{
    for(Long i = 0;i < 10;i++)
        g[1][i] = 1LL;
     
    for(Long i = 2;i <= 10;i++)
    {
        for(Long j = 0;j < 10;j++)
        {
            for(Long k = 0;k < 10;k++)
            {
                if(ABS(j - k) >= 2)
                    g[i][j] += 1LL * g[i - 1][k];
            }
        }
    }
}
 
Long bit[20];
Long len = 0;
Long get_res(Long k)//(0,k)
{
    memset(bit,0,sizeof(bit));
 
    len = 0;
     
    Long q = k;
    while(q)
    {
        bit[++len] = (q % 10LL);
        q /= 10LL;
    }
     
    Long result = 0;
     
    /*
        000x
        00xx
        0xxx...
    */
    for(Long i = 1;i < len;i++)
    {
        for(Long j = 1;j < 10LL;j++)
        {
            result += 1LL * g[i][j];//开头不可为0 
        }
    }
     
    /*
        1xxx
        2xxx
        3xxx
        .
        .
        (a-1)xxxx
    */
    for(Long i = 1;i <= bit[len] - 1;i++)
    {
        result += g[len][i];
    }
     
    /*
    a [0,b)[0,c)[0,d)...
    */
    for(Long i = len - 1;i >= 1;i--)
    {
        for(Long j = 0;j < bit[i];j++)//枚举第i位 
        {
            if(ABS(bit[i + 1] - j) >= 2LL)
                result += g[i][j];
        }
         
        if(ABS(bit[i] - bit[i + 1]) < 2LL)
            break;
    }
     
    return result;
}
 
int main()
{
     
    init();
     
    Long l = 0LL;
    Long r = 0LL;
     
    std::cin>>l>>r;
     
    Long result = get_res(r + 1LL) - get_res(l);
     
    //for(int i = 0;i <= 10;i++)
    //  for(int j = 0;j < 10;j++)
    //      std::cout<<i<<" "<<g[i][j]<<"\n";
            //printf("%d %d\n",i,g[i][j]);
     
    std::cout<<result<<std::endl;
     
    return 0;
}
 
_THIS_IS_END_OF_ARTICLE_

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter