数位DP——2018数,吉比特笔试题

题目:给定一个n求1到n之间的2018数,2018数数字中含有 2018即为2018数例如,210198,32108;10218不是2018数,

数据范围1e9;

解法:数位dp,数位dp理解,记忆话加递归,将每一位的数字状态保存下来,以后用到时直接调用结果

代码中写了我对此题的理解 ,可能对大家有点帮助,数位dp入门参看:https://blog.csdn.net/qq_37632935/article/details/81315404#commentBox 

#include<iostream>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<stdio.h>
#include<string.h>
using namespace std;

const int n = 11;
int dp[n][5][2];
int dat[5] = { 0,2,0,1,8 };
int num[n+1];

int dfs(int pos, int pn, int lim){
	if (pos == 0)return pn == 5 ? 1 : 0;//从高位向低位走到最后,5代表2018走完即前面出现了2018
	if (dp[pos][pn][lim]!=-1 && !lim)return dp[pos][pn][lim];//dp[pos][pn][lim]走过,并且当前是没有被限制,即可以随便取.记忆话
	int top = lim ? num[pos] : 9;//当前是被限制的则取当前位的值,否则去9,例子3567,当第一位去2时,第二位可以随便取,因为最大
	//为2999<3567
	int tn = 5;
	int ans = 0;
	for (int i = 0; i <= top; i++) {
		tn = 5;
		if(pn<5){//大于等于5即前面的位数已经出现2018的组合,后面的可以全部加起来了
			if (dat[pn] == i)tn = pn + 1;//当前位是预期结果,预期结果为向后移一位如,2018当前是2,那么,下次判断就应该判1了
			else tn = pn;
		}
		ans += dfs(pos - 1, tn, lim && (i == top));//当前位只有在前一位也受限制时才受限制。
	}
	if (!lim)dp[pos][pn][lim] = ans;
	return ans;
}


int main() {
	memset(dp, -1, sizeof(dp));
	int m;
	while (cin >> m) {
		int k = 0;
		while (m) {
			num[++k] = m % 10;
			m = m / 10;
		}
		cout << dfs(k, 1, 1);//k位数,从第k位(最高位)开始,第一个1代表dat的2,去判断是否是2,第二个1为当前是否有限制。
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章