zoukankan      html  css  js  c++  java
  • 数位dp从lv1到lv2

    上一篇windy数的记忆化搜索做法里,开了一个dp[pos][pre][lim][zero]数组,这个数组可以减少一维,把zero那维去掉,但是在dfs的参数里还是要保留zero的

    考虑到在记忆化搜索过程中,大部分数都是zero==0,只有少数数是zero==1,所以我们只对zero==0的情况做记忆化处理

    int dp[12][10][2]; // dp[pos][pre][lim]
    int dfs(int pos, int pre, bool lim,bool zero) {
    	if (~dp[pos][pre][lim]&&!zero) return dp[pos][pre][lim];
    	if (!pos) {
    		if (!zero) return dp[pos][pre][lim] = 1;//记忆化
    		else return 1;//不做记忆化处理
    	}
    	int res = 0;
    	int r = lim ? b[pos] : 9;
    	int l = zero ? 1 : 0;
    	for (int i = l; i <= r; i++) {
    		if (abs(i - pre) < 2) continue;
    		res += dfs(pos - 1, i, lim && i == r, 0);//不是最高位,可以取0
    	}
    	if (!zero) return dp[pos][pre][lim] = res;//记忆化
    	else return res;//不做记忆化处理
    }
    

      

    同样,lim这一维也是可以删掉的

    int dp[12][10]; // dp[pos][pre]
    int dfs(int pos, int pre, bool lim,bool zero) {
    	if (~dp[pos][pre]&&!zero&&!lim) return dp[pos][pre];
    	if (!pos) {
    		if (!zero&&!lim) return dp[pos][pre] = 1;//记忆化
    		else return 1;//不做记忆化处理
    	}
    	int res = 0;
    	int r = lim ? b[pos] : 9;
    	int l = zero ? 1 : 0;
    	for (int i = l; i <= r; i++) {
    		if (abs(i - pre) < 2) continue;
    		res += dfs(pos - 1, i, lim && i == r, 0);//不是最高位,可以取0
    	}
    	if (!zero&&!lim) return dp[pos][pre] = res;//记忆化
    	else return res;//不做记忆化处理
    }
    

      

    那么pre这一维呢,思考一下,感觉不行

    我试了一下,发现样例是过了,交一发试试,结果全wa了,看来对于这题来说还是不能删掉这一维

    因为windy数涉及到pos的前一位数对pos这位数的影响,所以dp数组里和dfs的参数里都要有pre

    而在有些其他题目里,比如 不要62,你甚至可以只开一维!! 用一维记忆化搜索!!

    那么减维有什么用呢,减维虽然减少了空间,但记忆化的东西少了,就增加了时间,在空间本来就很充足的情况下,减维是不合适的

    如果空间不够,可以考虑减维

    有时候,dfs的参数里也可以删掉zero这一项,比如题目说前导零的数也是合法的,或者把题目看成是前导零的数也是合法的,并不影响最终的输出

    gym102452J Junior Mathematician 2019ICPC 香港

    这题我一开始想出来的是开一个dp[5000][10][60][60][60][2][2]     (dp[pos][pre][su][f(x)%m][x%m][lim][zero])  的数组

    后来研究了好久题解才知道,这题把lim和zero两维删去了,同时这题不用考虑pre,dfs和dp数组里都没pre,同时dfs的参数也可以删掉zero这一项

    根据具体的题意可以把 f(x) % m 和 x % m 合并成 ( f(x) - x ) % m

    这样dp数组就变成了dp[5000][60][60] (dp[pos][su][mmm]  , mmm = ( f(x) - x ) % m)

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const long long MOD = 1e9 + 7;
    long long dp[5003][61][61];
    int pp[5003];
    int m;
    int b[5003];
    int tot = 0;
    long long dfs(int pos, int su, int mmm,bool lim) {
    	if (pos < 0) return 0;
    	if (~dp[pos][su][mmm]&&!lim) return dp[pos][su][mmm];
    	if (!pos && !lim) {
    		if(!mmm) return dp[pos][su][mmm] = 1;
    		return dp[pos][su][mmm] = 0;
    	}
    	if (!pos) {
    		if (!mmm) return 1;
    		return 0;
    	}
    	int l, r;
    	l = 0;
    	r = lim ? b[pos] : 9;
    	long long res = 0;
    	for (int j = l; j <= r; j++) {
    		res += dfs(pos - 1, (su + j) % m, ((mmm - j * pp[pos] + j * su) % m + m) % m, lim && j == r);
    	}
    	res %= MOD;
    	if (!lim) return dp[pos][su][mmm] = res;
    	else return res;
    }
    long long qiu(string s,int len) {
    	if (len < 2) return 0;
    	for (register int i = 0; i <= len; i++) {
    		for (int j = 0; j <= m; j++) {
    			for (int k = 0; k <= m; k++) {
    				dp[i][j][k] = -1;
    			}
    		}
    	}
    	for (int i = 1; i <= len; i++) {
    		b[i] = s[len - i + 1] - '0';
    	}
    	for (; !b[len]; len--);
    	long long res = 0;
    	return dfs(len, 0, 0, 1);//删去zero这一参数后,就只需从第len位开始搜
    }
    int main()
    {
    	int T;
    	pp[1] = 1;
    	string A, B;
    	cin >> T;
    	while (T--) {
    		cin >> A >> B >> m;
    		for (int i = 2; i <= 5000; i++) pp[i] = pp[i - 1] * 10 % m;
    		int lena = A.length();
    		int lenb = B.length();
    		A = " " + A;
    		B = " " + B;
    		A[lena]--;
    		for (int i = lena; i; i--) {
    			if (A[i] < '0') {
    				A[i] += 10;
    				A[i - 1]--;
    			}
    			else break;
    		}
    		cout << (qiu(B,lenb) - qiu(A,lena)+MOD)%MOD << endl;
    	}
    	return 0;
    }
    

      

    附上这题dfs的参数里没删去zero的代码

    long long dfs(int pos, int su, int mmm, bool lim, bool zero) {
    	if (pos < 0) return 0;
    	if (~dp[pos][su][mmm] && !lim && !zero) return dp[pos][su][mmm];
    	if (!pos && !lim && !zero) {
    		if (!mmm) return dp[pos][su][mmm] = 1;
    		return dp[pos][su][mmm] = 0;
    	}
    	if (!pos) {
    		if (!mmm) return 1;
    		return 0;
    	}
    	int l, r;
    	l = zero ? 1 : 0;
    	r = lim ? b[pos] : 9;
    	long long res = 0;
    	for (int j = l; j <= r; j++) {
    		res += dfs(pos - 1, (su + j) % m, ((mmm - j * pp[pos] + j * su) % m + m) % m, lim && j == r, 0);
    	}
    	res %= MOD;
    	if (!lim && !zero) return dp[pos][su][mmm] = res;
    	else return res;
    }
    long long qiu(string s, int len) {
    	if (len < 1) return 0;
    	for (register int i = 0; i <= len; i++) {
    		for (int j = 0; j <= m; j++) {
    			for (int k = 0; k <= m; k++) {
    				dp[i][j][k] = -1;
    			}
    		}
    	}
    	for (int i = 1; i <= len; i++) {
    		b[i] = s[len - i + 1] - '0';
    	}
    	for (; !b[len]; len--);
    	long long res = 0;
    	res = dfs(len, 0, 0, 1, 1);
    	for (int i = len - 1; i > 1; i--) {
    		res += dfs(i, 0, 0, 0, 1);//没删去zero这一参数,相当于要考虑前导零,就要加上这些		
    	}
    	res %= MOD;
    	return res;
    }
    

      

  • 相关阅读:
    HDU 5521 Meeting
    HDU 5170 GTY's math problem
    HDU 5531 Rebuild
    HDU 5534 Partial Tree
    HDU 4101 Ali and Baba
    HDU 5522 Numbers
    HDU 5523 Game
    ZUFE OJ 2301 GW I (3)
    POJ 2398 Toy Storage
    POJ 2318 TOYS
  • 原文地址:https://www.cnblogs.com/ruanbaitql/p/13834863.html
Copyright © 2011-2022 走看看