P8680 [蓝桥杯 2019 省 B] 特别数的和

暴力秒了

#include<bits/stdc++.h>
#define int long long//开long long是个好习惯
using namespace std;
bool baozi(int x)
{
    while(x)
    {
        int t = x % 10;
        if(t == 2 || t == 0 || t == 1 || t == 9) //数位判断
        {
            return true;
        }
        x /= 10;
    }
    return false;
}
signed main()
{
    int n , sum = 0;
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        if(baozi(i))//如果条件成立, 就让sum加上i
        {
            sum += i;
        }
    }
    cout << sum << endl;//最后输出所有满足条件的数的和
    return 0;
}

但是写的数位dp做法调不出来😂  只有50分

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <cmath>
#define For(i, j, n) for(int i = j ; i <= n ; ++i)
using namespace std;

int k, tar;
long long ans;

short flag;

int f(int x)
{
    if(x == 0)  return 0;
    if(x == 1)  return 1;
    if(x == 2)  return 2;
    if(x == 9)  return 3;
    return -1;
}

int powers[] = {1, 10, 100, 1000, 10000};

void solve(int n, int res, int p0, int p1, bool suc)
{
    if(res > tar) return;
    if(n == k + 1)
    {
       // cout << res << " " << flag << " " << suc << endl;
        if(flag && !(flag == 1 && !suc))
            ans += res;
        return;
    }
    for(int i = 0; i <= 9; i++)
    {
        int t = f(i);
        short b = flag;
        if(t >= 0)
            flag |= (1 << t);
        int t0 = ((!i)?n:p0);
        int t1 = (i?n:p1);
        solve(n + 1, res + i * powers[n - 1], t0, t1, suc | (t1 > t0));
        flag = b;
    }
}

int main()
{
    cin >> tar;
    k = log10(tar) + 1;
    solve(1, 0, 1, 0, 0);
    cout << ans << endl;
    return 0;
}

 更新:换了种写法,数位dp做法过了,核心思想:do it simple

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <cmath>
#define For(i, j, n) for(int i = j ; i <= n ; ++i)
using namespace std;

int k, tar;
long long ans;

int powers[] = {1, 10, 100, 1000, 10000};

void solve(int n, int res, int last, bool suc)
{
    if(res > tar) return;
    if(n == k + 1)
    {
        // cout << res << " "  << " " << suc << endl;
        if(suc)
            ans += res;
        return;
    }
    for(int i = 0; i <= 9; i++)
    {
        bool f = false;
        if(i == 1 || i == 2 || i == 9)  f = true;
        if(i > 0 && last == 0)   f = true;
        solve(n + 1, res + i * powers[n - 1], i, suc | f);
    }
}

int main()
{
    cin >> tar;
    k = log10(tar) + 1;
    solve(1, 0, -1, 0);
    cout << ans << endl;
    return 0;
}

注意last的初值不能为0,必须设置成一个负数,否则答案会偏大。

但事实上,这道题并不适合用数位dp来做,数位dp适合的场景:

数据范围非常大,且题目给出的条件很复杂,不好直接验证,于是我们直接按照这个规则来构造数字。

posted @ 2024-03-01 23:32  Gold_stein  阅读(6)  评论(0编辑  收藏  举报