zoukankan      html  css  js  c++  java
  • 土拨鼠猎人 数位DP

    问题描述
    Sparrow是一只土拨鼠。

    作为一只可爱又机智的土拨鼠,Sparrow常常被土拨鼠猎人们盯上。众所周知,土拨鼠很擅长打洞,他把每个洞按照1,2,3,4,……的顺序从小到大编号。为了迷惑土拨鼠猎人,Sparrow只选择了一些编号特殊的洞作为居住地。这些特殊的洞的编号满足以下几个条件:

    1.不含前导零。

    2.如果位数大于等于三位,则不存在连续三位数字构成“233”。如“15233”,“23345”就不是特殊编号的洞。

    3.如果位数大于等于三位,则不能同时满足存在“连续两位数字相等”和“某一个数字恰好等于它右边的数字加一”。如“13396”和“25481”满足条件,而“65377”则不行。

    4.特别地,1~99不足三位,它们也是特殊的编号。

    现在,天才土拨鼠猎人MLX得到可靠情报,Sparrow藏在编号第N小的特殊的洞里。你能告诉MLX这个洞的编号吗?

    解:
    记忆化搜索好啊!
    定义f[i][j][pr][r1][r2][bj][d] 表示第i+1位填j i+2位为pr r1表示是否有相同 r2 表示是否有递减 d表示是否有前导0

    关键是是否有前导0 这个需要特判!

    采用记忆化搜索解数位DP 更好更快
    code:

    //
    #include<bits/stdc++.h>
    #define ll long long
    #define maxnn 40
    ll f[maxnn][20][20][2][2];
    using namespace std;
    ll n;
    vector<ll > num;
    ll dfs(int i,int j,int pr,int r1,int r2,int bj,int d) {
    	if(i<=-1) return 1;
    	ll ans=0;
    	if((~f[i][j][pr][r1][r2])&&(!bj)) return f[i][j][pr][r1][r2];
    	int minn;
    	minn=(bj?num[i]:9);
    	if(r1==1&&r2==1) {
    		return 0;
    	}
    	int fla=0;
    	for(int k=0; k<=minn; k++) {
    		if(d&&k!=0) fla=0;
    		else
    		{
    			if(d&&(k==0)) fla=1;
    			else
    			{
    				if((!d)) fla=0;
    			}
    		}
    		if(k==3&&pr==2&&j==3) {
    			continue;
    		}
    		if(j==k+1&&(!d)) {
    			if(r2==1) {
    				continue;
    			} else {
    				ans+=dfs(i-1,k,j,1,0,(k==minn)&bj,fla);
    				continue;
    			}
    		} else if(j==k&&(!d)) {
    			if(r1==1) {
    				continue;
    			} else {
    				ans+=dfs(i-1,k,j,0,1,(k==minn)&bj,fla);
    				continue;
    			}
    		}
    		else
    		ans+=dfs(i-1,k,j,r1,r2,(k==minn)&bj,fla);
    	}
    	if(!bj) f[i][j][pr][r1][r2]=ans;
    	return ans;
    }
    ll isok(ll t) {
    	memset(f,-1,sizeof(f));
    	num.clear();
    	while(t) {
    		num.push_back(t%10);
    		t/=10;
    	}
    	return dfs(num.size()-1,-2,-2,0,0,1,1)-1;
    }
    int main() {
    	//freopen("tes","r",stdin);
    	//freopen("myp.out","w",stdout);
    	cin>>n;
    	ll l=0,r=1e18;
    	while(l<=r) {
    		ll mid=(l+r)>>1;
    		if(isok(mid)>=n) {
    			r=mid-1;
    		} else {
    			l=mid+1;
    		}
    	}
    	cout<<l;
    }
    
  • 相关阅读:
    java程序运行时内存分配详解 (转)
    android命令安装apk时报错:INSTALL_FAILED_CPU_ABI_INCOMPATIBLE
    android中的命令安装与卸载
    遇到问题的态度
    java中的Robot
    Python中*args 和**kwargs作为形参和实参时的功能详解
    python使用selenium执行JS快速完成超长字符串的输入
    python中多模块导入的注意点
    Python中的GIL锁
    不用下载Axure RP Extension for Chrome插件查看原型文件的方法
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11734914.html
Copyright © 2011-2022 走看看