【动态规划】[COCI]摘樱桃

来源:互联网 发布:2015淘宝刷钻价格表 编辑:程序博客网 时间:2024/06/09 15:20

这道题目实际上我们首先看看题目描述
摘樱桃(cherry) 拉娜生活在一个美丽的小村庄。在大街的一旁有一排樱桃树,编号从1到N. 在反复研究后,拉娜发现树的编号神奇的决定了这棵树的樱桃数。 对每一棵树,考虑树的编号中连续的几个数段,对每一数段,该数字乘上这个数段的长度的平方再全部相加,就得到这棵树能够结的樱桃数。 比如,树的编号是77744007,数段分别为777,44,00和7。樱桃数就是7*3^2+4*2^2+0*2^2+7*1^2=86个。 摘樱桃的时候到了,村民们同意把编号为A到B(包括A,B)的所有樱桃都摘下来。写一个程序计算,能摘到多少樱桃。
输入样例一:
1 9
输入样例二:
100 111
输入样例三:
7774407 7774407
输出样例一:
45
输出样例二:
68
输出样例三
86
首先我们可以发现令f(i)表示从1-i中的可以摘的樱桃,那么答案应该就是ans=f(B)f(A1)那么可以发现这是一个数位DP那么令f(i,j,d)表示当第i位为j的数字的所有的樱桃的数量和第三位表示的是当前构成f(i,j,d)的编码和是否严格小于A或者B的前i位所构成的数字(因为要特殊处理边界)(i从小到大对应的是A的从高位到个位)
然后分析一下很容易发现

f(i,Ai,1)=f(k,Ak,1)+(ik)2×Ai

那么如果d=0呢,可以发现有两种情况先说第一种k位之前的已经严格小于了A了那么当前就不用考虑任何东西所以
f(i,j,0)=k=0,z=0k<i,z<10f(k,z,0)+(ik)2×Ai×g(k,z,0)
这里的g(i,j,0)表示的是能够构成f(k,z,0)的总的方案数量,因为对于每一种后面都可以接上i-k这么一段,那么如果之前从k已经严格等于了那么就要从k+1开始(高位开始)一直到i判断如果有不相等的了,就判断是大还是小,如果是小于j那么显然当前如果i-k变成j就超过了A了,如果大于那么无论后面是否存在小于j这个数字i-k变成j不会超过A那么有
f(i,j,0)+=f(k,Bk,1)+(ik)2×Ai
然后答案就是
Ans=(i=0i<10f(n,i,0))+f(n,An,1)

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int MAXN = 16;LL dp[MAXN+2][10][2], g[MAXN+2][10][2], B[MAXN+10], n;LL f(int i, int j, int d){    if(!i) return 0;    if(dp[i][j][d]) return dp[i][j][d];    if(d){        int nowp=i;        do{nowp--;}while(B[nowp+1] == B[nowp]);        dp[i][j][d] = f(nowp, B[nowp], d) + 1LL * (i - nowp) * (i - nowp) * j * g[nowp][B[nowp]][1];    }else{        bool flag = B[i] <= j;        for(int k=i-1; k>=0; k--){            if(B[k+1] == j) flag=flag;            else flag=j>B[k+1];            int len = i - k;            for(int z=0;z<10;z++)                if(z != j)                    dp[i][j][d] += f(k, z, 0) + 1LL * len * len * j * g[k][z][0];            if(flag) continue;            if(B[k] != j || !k)                dp[i][j][d] += f(k, B[k], 1) + 1LL * len * len * j * g[k][B[k]][1];        }    }    return dp[i][j][d];}LL solve(LL u){    if(!u) return 0;    memset(dp, 0, sizeof dp);    memset(g, 0, sizeof g);    g[0][0][1] = 1LL;    char tmp[MAXN+5];    memset(tmp, 0, sizeof tmp);    int pos = 0;    while(u){        tmp[pos++] = u % 10 + '0';        u = u / 10;    }    n = strlen(tmp);    for(int i=0;i<n;i++)        B[i+1] = tmp[n-i-1]-'0';    for(int i=1;i<=n;i++){        for(int j=0;j<10;j++){            for(int k=0;k<10;k++)                g[i][j][0] += g[i-1][k][0];            if(j<B[i]) g[i][j][0] += g[i-1][B[i-1]][1];        }        g[i][B[i]][1] = 1;    }    LL ret = f(n, B[n], 1);    for(int z=0;z<10;z++)        ret += f(n, z, 0);    return ret;}int main(){    LL a, b;    while(cin>>a>>b){        cout<<solve(b) - solve(a-1)<<endl;    }    return 0;}
0 0
原创粉丝点击