HDU 3555 Bomb(数位DP)

来源:互联网 发布:通达信短线决策源码 编辑:程序博客网 时间:2024/05/29 07:00
BombTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 15793    Accepted Submission(s): 5754Problem DescriptionThe counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would add one point.Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them?InputThe first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description.The input terminates by end of file marker.OutputFor each test case, output an integer indicating the final points of the power.Sample Input3150500Sample Output0115HintFrom 1 to 500, the numbers that include the sub-sequence "49" are "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499",so the answer is 15.Authorfatboy_cw@WHUSource2010 ACM-ICPC Multi-University Training Contest(12)——Host by WHURecommendzhouzeyong
初次接触数位dp,内心舒畅,精神愉快。dp初始化的思想和之前的非010串差不多。1.dp[i][0]=10*dp[i-1][0]-dp[i-1][1]  2.dp[i][1]=dp[i-1][0]3.dp[i][2]=10*dp[i-1][2]+dp[i-1][1]1代表没有出现在i之前没用出现49的个数2代表i之前没有出现49可是最高位是9的个数,3代表i之前出现49的个数接下来是我对数位dp的理解:(这里的i之前是i到低位)1.第i位之前没有出现49的数的个数,那就是dp[i-1][0],由于第i位可以填0~9,所以是10*dp[i-1][0],并且当第i位填4的时候,如果第i-1位是之前没用出现49但最高位是9的,那就组成了49,所以不符合,那我们需要减去dp[i-1][1],所以dp[i][0]=10*dp[i-1][0]-dp[i-1][1]。2.第i位填9,排除第i位之前出现过49,还有第i位之前没用出现过49但最高位是9的,所以dp[i[1]=dp[i-1][0]3.第i位之前出现过49,第i位可以填0~9,所以是10*dp[i][2],当第i位填4的时候,我们需要加上第i-1为9的(能与第i位组成49),所以dp[i][2]=10*dp[i-1][2]+dp[i-1][1]计算N的时候,我们是从最高位算到最低位的.(i之前表示i到高位,i之后表示i到低位)从最高位开始:首先呢,当前位符合有49的数的个数为len[i]*dp[i-1][2],这里表示当前位可以填0~len[i]-1,所以为什么是len[i]>4才可以加上dp[i-1][1]组成49,原因就在这里,当len[i]=4时,我们在i位填的是0~3,并没有4。接着判断i之前是否出现过49(这里值*49*i***这样的,我们之前dp是**i**49这样的,要区分开),如果已经有49了,我们就要加上i往低位的没有出现过49的数的个数,即dp[i-1][0]*len[i]。如果没出现49的话,我们就要对当前位讨论,如果len[i]>4的话,我们就要加上dp[i-1][1],这样就可以组成49啦,所以这样的数字个数也要加上。(49***49这样的算一个,所以当前面出现49了,我们就不需要讨论当前为是否大于4,不需要加上len[i]*dp[i-1][1])为什么要讨论len[i+1]==4&&len[i]==9,是因为我们之前讨论是在i之后出现49的情况,可是没有讨论i之后没出现49可是之前出现49的情况,例如496000这样的数字,6之后没有出现49,可是6之前出现过49,那我们就要加上6*dp[i-1][0],以此类推,所以像这样的数我们也要加起来。判断这个条件是否成立,对后续有用。ret+1的原因是: dp的过程是算(1, ret)内出现49的数的个数,这里是不包含ret的,如果ret也刚好包含49,那么我们还要对ret进行讨论,如果ret+1,那样我们算的过程也包含了ret,这样就不用讨论ret啦,这样子是不是方便多了呢。终于写好了,不容易,第一次写这么多字,也希望大家能指出错误,一起学习。
#include<iostream>#include<cstring>#include<cstdlib>#include<algorithm>#include<cctype>#include<cmath>#include<ctime>#include<string>#include<stack>#include<deque>#include<queue>#include<list>#include<set>#include<map>#include<cstdio>#include<limits.h>#define fir first#define sec second#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)#define mes(x, m) memset(x, m, sizeof(x))#define pii pair<int, int>#define Pll pair<ll, ll>#define INF 1e9+7#define Pi 4.0*atan(1.0)#define MOD 1000000007#define lowbit(x) (x&(-x))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define ls rt<<1#define rs rt<<1|1typedef long long ll;typedef unsigned long long ull;const double eps = 1e-12;const int maxn = 4;using namespace std;inline int read(){    int x(0),f(1);    char ch=getchar();    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}ll dp[20][3];int len[20];void init(){    mes(dp, 0);    dp[0][0] = 1;    for(int i = 1; i < 20; ++i){        dp[i][0] = 10*dp[i-1][0] - dp[i-1][1];        dp[i][1] = dp[i-1][0];        dp[i][2] = 10*dp[i-1][2] + dp[i-1][1];    }}int getlen(ull num){    int t = 0;    while(num){        len[++t] = num%10;        num = num/10;    }    return t;}void solve(ull num){    int t = getlen(num);    ull res = 0;    bool flag = false;    for(int i = t; i >= 1; --i){        res += (ull)len[i]*dp[i-1][2];        if(flag){            res += (ull)len[i]*dp[i-1][0];        }        if(!flag && len[i] > 4){            res += dp[i-1][1];        }        if(4==len[i+1] && 9==len[i]){            flag = true;        }    }    cout << res << endl;}int main(){    int Case;    Case = read();    ull ret;    init();    while(Case--){        cin >> ret;        mes(len, 0);        solve(ret+1);    }    return 0;}
1 0
原创粉丝点击