题意: 统计n以内含49的数的个数。
题解: 定义状态dp[i][]
- dp[i][0]表示i位数里不含49的个数。
- dp[i][1]表示i位数里不含49,但首位是9的个数。
- dp[i][2]表示i位数里含49的个数。
过程中犯的错:
- dig数组忘记初始化,影响下一次数据的答案。
一般DP
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t, dig[65];
ll n, dp[65][3];
void init(){
dp[0][0] = 1, dp[0][1] = dp[0][2] = 0;
for(int i = 1; i < 65; i++){
dp[i][0] = dp[i - 1][0] * 10 - dp[i - 1][1];
dp[i][1] = dp[i - 1][0];
dp[i][2] = dp[i - 1][1] + dp[i - 1][2] * 10;
}
}
ll f(int len){
int flag = 0; ll ans= 0;
for(int i = len ; i > 0 ; i--){
ans += dp[i - 1][2] * dig[i];
if(flag) ans += dp[i - 1][0] * dig[i];
if(!flag && dig[i] > 4) ans += dp[i - 1][1];
if(dig[i + 1] == 4 && dig[i] == 9) flag = 1;
}
return ans;
}
int main(){
init();
scanf("%d", &t);while(t--){
scanf("%lld", &n);
int len = 0; ll tem = n + 1;
memset(dig, 0, sizeof dig);
dig[++len] = tem % 10;
while(tem /= 10) dig[++len] = tem % 10;
printf("%lld\n", f(len));
}
return 0;
}
记忆化搜索
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t, len, dig[65];
ll n, dp[65][3];
ll dfs(int len, bool ismax, int ts){
if(!len) return ts == 2;
if(!ismax && dp[len][ts]) return dp[len][ts];
ll ans = 0; int maxx = (ismax? dig[len]: 9);
for(int i = 0; i <= maxx; i++){
if(ts == 2 || ts == 1 && i == 9)
ans += dfs(len - 1, ismax && i == maxx, 2);
else if(i == 4)
ans += dfs(len - 1, ismax && i == maxx, 1);
else ans += dfs(len - 1, ismax && i == maxx, 0);
}
if(!ismax) dp[len][ts] = ans;
return ans;
}
int main(){
dp[0][0] = 1, dp[0][1] = dp[0][2] = 0;
scanf("%d", &t);while(t--){
scanf("%lld", &n);
memset(dig, 0, sizeof dig);
dig[len = 1] = n % 10;
while(n /= 10) dig[++len] = n % 10;
printf("%lld\n", dfs(len, true, 0));
}
return 0;
}