hihoCoder #1033 交错和

hihoCoder #1033 交错和

题目链接 #1033交错和

题目大意:

​ 题意很清楚,就是求区间满足条件的数字的和

思路:
-  这是一道数位dp的题目
-  注意返回值,因为要算数字和,所以在进行 $dfs$ 搜索时,要返回两个值,一个是满足条件的个数 $n$ ,一个是满足条件的总和$sum$,所以当前位置的贡献就是 当前填的数乘上个数,累加取模即可。
-  要注意前导 $0$ ,因为前导 $0$ 会影响状态
-  具体可以看代码
代码:
#include <bits/stdc++.h>
using namespace std;
#define me(a, b) memset(a, b, sizeof(a))
#define IOS() ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
#define chcek(x) x>=0?x:200-x
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 5;
const ll mod = 1e9 + 7;

int dig[20];
ll k;
//   even zero limit pos sum
pll dp[2][2][2][20][400];
bool vis[2][2][2][20][400];

ll mpow(ll x)
{
    ll res = 1;
    while(x) {
        res *= 10;
        --x;
    }
    return res % mod;
}

// 因为 sum 可能是负数, 所以需要加一个偏移量
// pair 第一个是满足条件的个数, 第二个是累加和
//     偶数位       前导0       上限      位置      数位和
pll dfs(int even, int zero, int limit, int pos, int sum)
{
    pll ans(0, 0);
    if(pos < 0) {
        if(sum == k)
            ans.first = 1;
        return ans;
    }
    // 记忆化搜索
    if( vis[even][zero][limit][pos][chcek(sum)] )
        return dp[even][zero][limit][pos][chcek(sum)];
    vis[even][zero][limit][pos][chcek(sum)] = true;

    ll d = mpow(pos);
    for(int i = 0; i < 10; ++i) {
        // 超出界限
        if(limit && i > dig[pos]) break;
        pll p;
        // 前导0, 偶数位就不可以改变
        if(zero && !i)
            p = dfs(even, zero, limit&&i==dig[pos], pos-1, sum);
        else // 正常情况
            p = dfs(!even, 0, limit&&i==dig[pos], pos-1, sum + (even?i:-i));
        ans.first = (ans.first + p.first) % mod;
        ans.second += i*d*p.first%mod + p.second;
        ans.second %= mod;
    }
    return dp[even][zero][limit][pos][chcek(sum)] = ans;
}

ll solve(ll n)
{
    me(vis, 0);
    int cnt = 0;
    while(n) {
        dig[cnt++] = n % 10;
        n /= 10;
    }
    return dfs(1, 1, 1, cnt-1, 0).second;
}

int main()
{
    IOS();
    ll l, r;
    cin >> l >> r >> k;
    ll ans = solve(r) - solve(l-1);
    ans = (ans + mod) % mod;
    cout << ans << endl;
    
    return 0;
}
总结:

​ 这题写了一个上午,第一就是因为前导 0 0 0 的问题,调试半天才发现,第二个就是取模的问题,在算 10 10 10 的幂次的时候,忘了取模,导致爆 l o n g l o n g longlong longlong,还是要多注意细节

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值