• 洛谷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;
    }
    
    
    
    
    
  • 相关阅读:
    rwkj 1337
    poj 1002
    map
    vector
    sort排序
    sort函数
    poj 2945
    poj2388
    rwkj 1422搜索(素数环)
    poj2503
  • 原文地址:https://www.cnblogs.com/et3-tsy/p/13215945.html
Copyright © 2020-2023  润新知