HDU 4734 F(x) ★(数位DP)
题意
一个整数 (AnAn-1An-2 ... A2A1), 定义 F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1,求[0..B]内有多少数使得F(x) <= F(A)。多组数据,T <= 10000思路
成都网赛……都是泪T_T…… 很裸的数位DP……一开始我的dp状态是dp[pos][fx],fx表示当前枚举到fx为多少,判断fx<=fa。但这样设计状态的一个问题是对于不同的A,dp[][]表示的状态不同,所以每个T都有memset dp数组,并且重新计算,然后就超时了哭…… 后来被nocLty指点……dp状态设计成dp[pos][remain],remain表示还剩多少fA可以分配,判断remain>=0。这样对于不同的A便不影响他的状态表示。所以不用每次T都重新计算dp[][],大大缩短了时间。 总结一下,在设计数位DP状态时最好把每次询问的变量作为初始值而不是状态转移、判定时依赖的量(比如第一个状态判定条件是fx<=fa,就依赖于当前fa,这样就不好),这样才可以最大限度的发挥记忆化的作用。代码
[cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; vector <int> num; int dp[11][10000]; int dfs(int pos, int remain, int limit){ if (pos == -1){ return (remain >= 5000); } if (!limit && ~dp[pos][remain]) return dp[pos][remain]; int end = limit?num[pos]:9; int res = 0; for (int i = 0; i <= end; i ++){ res += dfs(pos-1, remain-(1<<pos)*i, limit && (i == end)); } if (!limit){ dp[pos][remain] = res; } return res; } int main(){ int t; scanf("%d", &t); MEM(dp, -1); for (int ca = 1; ca <= t; ca ++){ int A, B; scanf("%d %d", &A, &B); num.clear(); while(B){ num.push_back(B % 10); B /= 10; } int fa = 0; for (int i = 0; A; A /= 10, ++ i){ fa += (1 << i) * (A % 10); } printf("Case #%d: %d\n", ca, dfs(num.size()-1, 5000+fa, 1)); } return 0; } [/cpp]举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG