• luogu2657-Windy数题解--数位DP


    题目链接

    https://www.luogu.org/problemnew/show/P2657

    分析

    第一道数位DP题,发现有点意思

    DP求([L,R])区间内的XXX个数,很套路地想到前缀和,先求([1,R],[1,L])相减就好了

    状态转移也明确,发现状态只和上一位数位的数有关,(f[i][j])表示第(i)位放(j)的话有多少个windy数,注意的这里的windy数是在钦定一个数字最高位是多少情况下所有的windy数的数量和(即[1,i-1]位放数情况都被算了一遍)

    (f[i][j] = f[i-1][ j-2/j+2])

    然后考虑怎么求答案.

    假如我们要求(1)(R)中的windy数有多少,设R有x位,第i位数字为num[i]

    首先对于位数小于(x)的以及第(x)位数字小于(num[x])都可以算进去

    然后考虑卡到R边界的情况,我们可以枚举前k位卡到了上限即前(k)位与R的前(k)位相同,那么在第(k+1)位进行答案统计

    首先我们是不能达到上界的(这样的话可能算多次),在枚举(k+1)位的数字为(d)时根据定义只有当(abs(d-a[k])>=2)时才能累计答案

    但是还有一个问题就是你本身枚举与R相等的前k位数可能就违反了windy数的定义,那么我们需要特判一下退出,但是还需要注意由于这个原因我们需要倒序枚举,因为正序枚举的话如果你前面有一对数是非法的,无论后面数位为何值整个数就是非法的

    还有一些奇奇怪怪的问题比如前导(0).不过这个也挺好想的.

    最后发现如果(R)也是个windy数的话没判到(我们的卡上界实际上是没有卡到的,我们总是在当前枚举的这一位比R小),所以特判一下就好了

    代码

    /*
      code by RyeCatcher
    */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cctype>
    #include <utility>
    #include <queue>
    #include <vector>
    #include <ext/pb_ds/hash_policy.hpp>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <iostream>
    #define DEBUG freopen("dat.in","r",stdin);freopen("wa.out","w",stdout);
    #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
    #define ri register int
    #define ll long long
    #define ull unsigned long long
    #define SIZE 1<<22
    using std::min;
    using std::max;
    using std::priority_queue;
    using std::queue;
    using std::vector;
    using std::pair;
    using namespace __gnu_pbds;
    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    #define gc getchar
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=12;
    const int inf=0x7fffffff;
    int a,b;
    int toa=0,numa[maxn],tob=0,numb[maxn],f[maxn][maxn];
    int main(){
    	int x,y;
    	read(a),read(b);
    	for(ri i=0;i<=9;i++)f[1][i]=1;
    	x=a;
    	while(x){
    		numa[++toa]=x%10;
    		x=x/10;
    	}
    	x=b;
    	while(x){
    		numb[++tob]=x%10;
    		x=x/10;
    	}
    	bool flag=1;
    	for(ri i=2;i<=tob;i++)if(abs(numb[i]-numb[i-1])<2){flag=0;break;}
    	for(ri i=2;i<=tob;i++){
    		for(ri j=0;j<=9;j++){
    			for(ri k=0;k<=9;k++){
    				if(abs(k-j)>=2)f[i][j]+=f[i-1][k];
    			}
    		}
    	}
    	ll ans=0;
    	ans+=flag;
    	for(ri i=1;i<numb[tob];i++)ans+=f[tob][i];
    	for(ri i=1;i<tob;i++){
    		for(ri j=1;j<=9;j++)ans+=f[i][j];
    	}
    	for(ri i=tob-1;i>=1;i--){
    		for(ri j=0;j<numb[i];j++){
    			if(abs(j-numb[i+1])>=2)ans+=f[i][j];
    		}
    		if(abs(numb[i]-numb[i+1])<2)break;
    	}
    	for(ri i=1;i<numa[toa];i++)ans-=f[toa][i];
    	for(ri i=1;i<toa;i++){
    		for(ri j=1;j<=9;j++)ans-=f[i][j];
    	}
    	for(ri i=toa-1;i>=1;i--){
    		for(ri j=0;j<numa[i];j++){
    			if(abs(j-numa[i+1])>=2)ans-=f[i][j];
    		}
    		if(abs(numa[i]-numa[i+1])<2)break;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
    
  • 相关阅读:
    maven的安装教程
    webstorm的中文教程和技巧分享
    WebStorm
    grunt配置任务
    grunt快速入门
    CSS简介
    浅介HTML DOM
    【转】计算机是如何启动的?
    【转】深入理解C++中public、protected及private用法
    【转】VS2013动态库文件的创建及其使用详解
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9843805.html
Copyright © 2020-2023  润新知