EOJ3257 七减一(数位dp)

3257. 七减一

Time limit per test: 2.0 seconds

Memory limit: 256 megabytes

仲马是一个很七减一的人,他经常会说七减一七减一七减一,你们也许觉得他说的是 666,但实际上七减一是比 6 更为高贵的存在。仲马所有的表情包和打出来的数字中都要把 6 换成七减一。校赛临近了,仲马的七减一之魂开始燃烧了,他竟然想要打出 l 到 r 之间所有的数字并且将里面所有的 6 替换成七减一,然而当他完成这一切时他早已忘记了他打出了多少个高贵的七减一,为此他十分痛苦,你能告诉他他究竟将多少个 6 替换为了七减一么?

EOJ3257 七减一(数位dp)_第1张图片

Input

不超过 100 组输入,处理到文件结束。

每组数据一行,有两个数字 l,r,用空格分开。

对于 40% 的数据,满足:1lr104
对于 100% 的数据,满足:1lr1018

Output

每组数据输出一行结果。

Examples

input
1 6
1 666
output
1
201

题解:数位dp

dp[i][j]表示i位数最高位为j的所有数中6的个数总和。

先用init预处理出所有dp[i][j]

再找出所有小于x的数中6的个数,具体方法也是和杭电那道不要62相似

要注意的是当高位为6时需要加上剩下所有数的个数(因为开头那个数是6)

具体实现见代码。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define vi vector
#define ll long long
#define P pair
using namespace std;
const int maxn = 1e6 + 10;
bool lucky[maxn];
ll f[20][20];//f[i][j]表示i位数中最高位为j的所有数中所满足条件的数的个数
ll ten(int t)
{
    ll tmp = 1;
    for(int i = 0; i < t; i++)
        tmp *= 10;
    return tmp;
}
void init_dp()
{
    for(int i = 0; i <= 9; i++)
        if(i == 6) f[1][i] = 1;
    for(int i = 2; i <= 19; i++)//数的位数
        for(int j = 0; j <= 9; j++)
        {
            for(int k = 0; k <= 9; k++)
                f[i][j] += f[i - 1][k];
            if(j == 6) f[i][j] += ten(i - 1);
        }
}
ll count(ll t)
{
    int digit[20]={0};//记录每一位的数
    int num = 1;
    while(t)
    {
        digit[num++] = t % 10;
        t /= 10;
    }
    ll ans = 0;
    for(int i = num - 1; i >= 1; i--)
    {
        for(int j = 0; j < digit[i]; j++)
        {
            ans += f[i][j];
        }
        if(digit[i] == 6){
            ll temp = 0;
            for(int j = i - 1; j >= 1; j--)
                temp = temp * 10 + digit[j];
            ans += temp;
        }
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    init_dp();
    ll n, m;
    while(cin >> n >> m)
    {
        cout << 1LL * (count(m + 1) - count(n)) << endl;
    }
    return 0;
}

你可能感兴趣的:(DP)