zoukankan      html  css  js  c++  java
  • 洛谷 P3413 SAC#1

    Description

    洛谷传送门

    Solution

    典型的数位dp

    题目要求求区间 ([l, r]) 内有多少个数至少有长度为 2 的回文串。

    不难发现,我们只需要考虑长度为 2 或 3 的回文串即可。

    所以我们记忆化搜索时,存一下当前数的前一个数,和前前个数,判断一下即可。

    具体看代码吧,感觉挺好理解的。

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 1010
    #define ll long long
    
    using namespace std;
    
    const ll mod = 1e9 + 7;
    ll l1, l2, l, r;
    ll num[N], dp[N][10][10];
    char s1[N], s2[N];
    
    void init(){
        scanf("%s%s", s1 + 1, s2 + 1);
        l1 = strlen(s1 + 1);
        l2 = strlen(s2 + 1);
        for(ll i = 1; i <= l1; i++)
            l = ((l * 10) % mod + s1[i] - '0') % mod;
        for(ll i = 1; i <= l2; i++)
            r = ((r * 10) % mod + s2[i] - '0') % mod;
        return;
    }
    
    ll dfs(ll len, ll a, ll b, ll flag, ll lim){ //a 表示前一位, b 表示前前位, flag 判断前导0, lim 判断前一位是否到最高位
        if(!len) return 1;
        if(!flag && !lim && a != -1 && b != -1 && dp[len][a][b] != -1) return dp[len][a][b];
        ll x = lim ? num[len] : 9;
        ll res = 0;
        for(ll i = 0; i <= x; i++){
            if(i == a || i == b) continue;
            if(flag && !i) res = (res + dfs(len - 1, -1, -1, 1, lim && (i == x))) % mod;//是前导 0 的话,a 和 b 都赋值为 -1
            else res = (res + dfs(len - 1, i, a, 0, lim && (i == x))) % mod;
        }
        if (!flag && !lim && a != -1 && b != -1) dp[len][a][b] = res;
        return res;
    }
    
    ll solve(){
        memset(dp, -1, sizeof(dp));
        for(ll i = 1; i <= l1; i++)
            num[l1 - i + 1] = s1[i] - '0';
        ll ans1 = dfs(l1, -1, -1, 1, 1);//计算的是 1 ~ l 中非萌数个数
        ans1--;//假设 l 是萌数,1 ~ l-1 中非萌数个数 -1
        for(ll i = 1; i <= l2; i++)
            num[l2 - i + 1] = s2[i] - '0';
        ll ans2 = dfs(l2, -1, -1, 1, 1);//此时 ans 为 l+1 ~ r 中非萌数个数
        for(int i = 2; i <= l1; i++)//判断 l 是否为萌数,若 l 为萌数,则补回来,暴力判断
            if(s1[i] == s1[i - 1] || (s1[i] == s1[i - 2] && i - 2 >= 1)){
                ans1++;
                break;
            }
        return ans2 - ans1;
    }
    
    int main(){
        init();
        printf("%lld
    ", ((r - l - solve() + 1) % mod + mod) % mod);//前缀和思想
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15374611.html

  • 相关阅读:
    NoSuchElementException if input is exhausted 报错
    批量更改文件后缀名
    初识Java
    简单cmd
    电脑操作简易快捷键
    java学习 Markdown+开始写博客
    JavaScript基础知识
    当数位数不够这,前面补0
    vs code 设置
    json日期格式转换为 2019-11-27 格式
  • 原文地址:https://www.cnblogs.com/xixike/p/15374611.html
Copyright © 2011-2022 走看看