zoukankan      html  css  js  c++  java
  • P2657 【[SCOI2009]windy数】 数位DP板子题

    转自 https://www.luogu.com.cn/blog/ljc20020730/solution-p2657

    一起学下数位dp

    • 设f(x)表示x前面的数 即 t∈[1,x) 中windy数的个数

    那么显然如果要求 [l,r]中windy数的个数就是:

    • F(l,r) = f(r+1)-f(l)

    数位dp开始,预处理位数为i最高位为j的windy数个数 f[i][j]

    转移:

    • f[i][j]=f[i-1][k] | 其中k是非负整数k∈[0,9]且|k-j|>=2

    初始值:

    • f[1][i]=1 | 其中i为非负整数 i∈[0,9]

    求f(x)怎么求呢?

    为了方便处理先对数x进行按10进制位拆分到a[]数组

    • 显然位数比x要小的数字都是合法的都在[1,x)区间内,直接统计就行
    • 位数和x一样最高位的数字比x小的数字都是合法的都在[1,x)区间内直接统计就行
    • 位数和x一样,最高位又和x一样我们从左到右扫一遍x各个位子上的数字大小然后枚举合法的该位子上的数[0,9]判断是否合法就行。
    ll f[15][15];
    int a[15];
    ll fun(ll x)
    {
        int len=0;
        while (x>0ll) a[++len]=x%10,x/=10;
        ll sum=0ll;
        for (int i=1;i<=len-1;i++)
         for (int j=1;j<=9;j++)
          sum+=f[i][j];
        for (int i=1;i<a[len];i++) sum+=f[len][i];
    //这最后一个循环 其实没包括X这个数本身啊 算的是1~x-1的 所以下面调用的时候是m+1
    for (int i=len-1;i>=1;i--) { for (int j=0;j<=a[i]-1;j++) if (abs(j-a[i+1])>=2) sum+=f[i][j]; if (abs(a[i+1]-a[i])<2) break; //这一位不行后面的位子一定不行 } return sum; } int main() { ll n,m; scanf("%lld %lld",&n,&m); if (n>m) swap(n,m); for (int i=0;i<=9;i++) f[1][i]=1ll; for (int i=2;i<=10;i++) for (int j=0;j<=9;j++) for (int k=0;k<=9;k++) if (abs(k-j)>=2) f[i][j]+=f[i-1][k]; printf("%lld ",fun(m+1)-fun(n)); return 0; }
  • 相关阅读:
    iostream与iostream.h的区别
    [HAOI2011]向量
    [POI2011]Temperature
    [洛谷2839/国家集训队]middle
    [TJOI2013]松鼠聚会
    [HNOI2015]接水果
    [BZOJ3772]精神污染
    [BZOJ3251]树上三角形
    [ZJOI2011]道馆之战
    [SDOI2013]森林
  • 原文地址:https://www.cnblogs.com/acmLLF/p/13474308.html
Copyright © 2011-2022 走看看