zoukankan      html  css  js  c++  java
  • 洛谷P2657 Windy数 (数位DP)

    洛谷P2657 Windy数 (数位DP)

    https://www.luogu.com.cn/problem/P2657

    不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。Windy 想知道,在 a 和 b 之间,包括 a 和 b ,总共有多少个 windy 数?

    思路:

    数位DP

    首先我们用前缀和的思想让ans(a,b)转换成ans(0,b)-ans(0,a-1)

    那么如何求解某个值到0有多少windy数嘞?

    我们观察一下,如3421,我们先全考虑有前导0

    对于 第一位3 而言,当我们取它为2的时候,即0000 - 2999时

    数的枚举范围是确定的,非首位均是0->9,而首位是0->(num-1)

    这块很容易列出状态转移方程进行求解,这种全填充型的可以预处理得到的

    (开一个二维数组,分别记录位置以及首数字)

    而当首位取了3,我们不难发现它的答案实质上与3199是一样

    也就是说,我们在考虑3?...的时候,会出现两类情况

    1)首位后一位 " ?"首位 构成非法关系

    那么这里显然就像上面的例子一样,我们只要考虑小于" ?",且与首位合法的情况即可,直接利用前面预处理得到的全填充型

    2)首位后一位 " ?"首位 构成合法关系

    那么其实这一步也就是取了首位后一位,再把这个结果继承给 当前的首位,再去算小于且合法的情况即可

    进行完上面的过程后我们开始要考虑处理前导0的情况

    我们在上面DP的过程中,把01..以及00...这种情况筛掉了,即前导0不应与首位形成非法关系

    所有我们要把这部分的补回来,值得注意的是0000000这种,等价是0(补回0要特判下)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define maxn 15
    #define minn -105
    #define ll long long int
    #define ull unsigned long long int
    #define uint unsigned int
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'|ch>'9')last=ch,ch=getchar();
        while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
        if(last=='-')ans=-ans;
        return ans;
    }
    int unlimit[13][10];
    
    int cal(int cur)
    {
        if(cur<10)return cur;
        int pre=12,num=0,pos=0;
        int limit=1;
        while(1)
        {
            if(!cur)break;
            num=cur%10;
            cur/=10;
            pos++;
    
            if(abs(pre-num)<=1)limit=0;
    
            for(int i=0;i<min(10,pre);i++)
            {
                if(abs(i-num)>1)limit+=unlimit[pos-1][i];
            }
            pre=num;
        }
        //cout<<limit<<endl;
        for(int i=0;i<num;i++)
        {
            limit+=unlimit[pos][i];
        }
        while((pos--)>=1)
        {
            limit+=unlimit[pos][1];
            if(pos>1)limit+=unlimit[pos][0];
        }
        //cout<<limit<<endl;
        return limit;
    }
    
    int main()
    {
        int a,b;
        for(int i=0;i<10;i++)
            unlimit[1][i]=1;
    
        for(int pos=2;pos<11;pos++)
        {
            for(int i=0;i<10;i++)
            {
                for(int j=0;j<10;j++)
                   if(abs(i-j)>1) unlimit[pos][i]+=unlimit[pos-1][j];
                //cout<<pos<<"   "<<i<<"  "<<  unlimit[pos][i]<<endl;
            }
        }
        cin>>a>>b;
        cout<<cal(b)-cal(a-1)<<"
    ";
        return 0;
    }
    
    
    
    
    
  • 相关阅读:
    896. Monotonic Array单调数组
    865. Smallest Subtree with all the Deepest Nodes 有最深节点的最小子树
    489. Robot Room Cleaner扫地机器人
    JavaFX
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
    《Python CookBook2》 第一章 文本
  • 原文地址:https://www.cnblogs.com/et3-tsy/p/13215945.html
Copyright © 2011-2022 走看看