您的位置:首页 > 其它

HDU - 3555 Bomb (数位dp)

2018-03-11 14:24 295 查看
题目链接:https://cn.vjudge.net/contest/163023#problem/D

题目大意:要求1~n的范围内含有49的数字的个数

题目分析:做的数位dp的第二道题,有三种方法。

第一种(自己想到的):

求出1~n范围内不含49的个数,然后用总数减去不含49的个数再加一(多减了一个0)

代码如下:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
int data[30];
ll dp[30][2];

ll dfs(int pos, int pre, bool limit)
{
if(pos == -1) return 1;
if(!limit && dp[pos][pre == 4])
{
return dp[pos][pre == 4];
}
int up = limit ? data[pos] : 9;
ll ans = 0;
for(int i = 0; i <= up; i++)
{
if(i == 9 && pre == 4) continue;
ans += dfs(pos - 1, i, limit && i == data[pos]);
}
if(!limit) return dp[pos][pre == 4] = ans;
return ans;
}

ll solve(ll n)
{
memset(dp, 0, sizeof(dp));
int pos = 0;
while(n)
{
data[pos++] = n % 10;
n /= 10;
}
ll ans = dfs(pos - 1, -1, true);
return ans;
}

int main()
{
ll n;
int t;
scanf("%d", &t);
while(t--)
{
scanf("%lld", &n);
printf("%lld\n", n - solve(n) + 1);
}
return 0;
}


第二种方法:

假设n是123456, 当dfs到049_ _ _时,很显然,后三位可放置任意数,共有10 * 10 * 10种放置方法,这种是!limit的情况,当n是49123时,我们跑到49

_ _ _时,后边就只有123 + 1种方法。所以只要标记好limit,预处理出没有限制的情况,就可以轻松算出结果。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll dp[30][2], kind[30], n;
int data[30];

ll dfs(int pos, int pre, bool limit)
{
if(pos == -1) return 0;
if(!limit && dp[pos][pre == 4]) return dp[pos][pre == 4];
int up = limit ? data[pos] : 9;
ll ans = 0;

for(int i = 0; i <= up; i++)
{
if(pre == 4 && i == 9)
{
ans = ans + (limit ? ((n % kind[pos]) + 1) : kind[pos]);
}
else ans += dfs(pos - 1, i, limit && i == data[pos]);
}
if(!limit)
return dp[pos][pre == 4] = ans;
return ans;
}

ll solve(ll k)
{
int pos = 0;
memset(dp, 0, sizeof(dp));
while(k)
{
data[pos++] = k % 10;
k /= 10;
}

return dfs(pos - 1, -1, true);
}

int main()
{
int t, i;
kind[0] = 1;
for(i = 1; i <= 18; i++)
kind[i] = kind[i - 1] * 10;

scanf("%d", &t);
while(t--)
{
scanf("%lld", &n);
printf("%lld\n", solve(n));
}
}


第三种方法:

就是传统的数位dp,当时实在是太差了,这都想不出来。。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll dp[30][30][2], n;
int data[30];

ll dfs(int pos, int pre, bool sta, bool limit)
{
if(pos == -1 && sta) return 1;
if(pos == -1 && !sta) return 0;

if(!limit && dp[pos][pre == 4][sta]) return dp[pos][pre == 4][sta];
int up = limit ? data[pos] : 9;
ll ans = 0;

for(int i = 0; i <= up; i++)
{
if(pre == 4 && i == 9) ans += dfs(pos - 1, i, true, limit && i == data[pos]);
else ans += dfs(pos - 1, i, sta/*注意这里是sta,而不是false, 之前出过错。*/, limit && i == data[pos]);
}

if(!limit) return dp[pos][pre][sta] = ans;
return ans;
}

ll solve(ll k)
{
int pos = 0;
memset(dp, 0, sizeof(dp));
while(k)
{
data[pos++] = k % 10;
k /= 10;
}
return dfs(pos - 1, -1, false, true);
}

int main()
{
int t, i;
scanf("%d", &t);
while(t--)
{
scanf("%lld", &n);
printf("%lld\n", solve(n));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp