LUOGU P3413 SAC#1 - 萌数(数位dp)

传送门

解题思路

  首先这道题如果有两个以上长度的回文串,那么就一定有三个或两个的回文串,所以只需要记录一下上一位和上上位填的数字就行了。数位\(dp\),用记忆化搜索来实现。设\(f[i][j][k][0/1]\)表示填到了第\(i\)位,上上位数字为\(j\),上一位数字为\(k\),\(0/1\)表示有没有出现过回文串的方案数。\(dfs\)里在套路的传一个这一位有没有限制和前导0,细节还是比较多的。

代码

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
const int MAXN = 1005;
const int MOD = 1e9+7;
typedef long long LL;

string l,r;
int cnt,num[MAXN];
LL f[MAXN][15][15][2];

LL dfs(int x,int pre,int pree,bool lim,bool zero,int exist){
    if(x==0) return exist;
    int Max=lim?num[x]:9,p;LL sum=0;
    if(f[x][pre][pree][exist]!=-1 && !lim && !zero) return f[x][pre][pree][exist];
    for(int i=0;i<=Max;i++){
        p=(zero&&i==0)?-1:i;
        int A=pre,B=pree;
        sum+=dfs(x-1,pree,p,(lim&&(p==num[x])),(p==-1),exist|(p!=-1 && (pree==p || pre==p)));
        sum%=MOD;
    }
    if(!zero && !lim) f[x][pre][pree][exist]=sum;
    return sum;
}

LL solve(string s,bool sub){
    cnt=s.length();
    for(int i=1;i<=cnt;i++)
        num[cnt-i+1]=s[i-1]-‘0‘;
    if(sub){
        int now=1;
        while(num[now]==0) num[now++]=9;
        num[now]--;
        while(!num[cnt] && cnt) cnt--;
    }
    memset(f,-1,sizeof(f));
    return dfs(cnt,-1,-1,1,1,0);
}

int main(){
    cin>>l>>r;
    printf("%lld",((solve(r,0)-solve(l,1))%MOD+MOD)%MOD);
    return 0;
}

原文地址:https://www.cnblogs.com/sdfzsyq/p/9813442.html

时间: 2024-10-08 18:36:51

LUOGU P3413 SAC#1 - 萌数(数位dp)的相关文章

luogu 3413 SAC#1 - 萌数

题目描述 辣鸡蒟蒻SOL是一个傻逼,他居然觉得数很萌! 好在在他眼里,并不是所有数都是萌的.只有满足“存在长度至少为2的回文子串”的数是萌的——也就是说,101是萌的,因为101本身就是一个回文数:110是萌的,因为包含回文子串11:但是102不是萌的,1201也不是萌的. 现在SOL想知道从l到r的所有整数中有多少个萌数. 由于答案可能很大,所以只需要输出答案对1000000007(10^9+7)的余数. 输入输出格式 输入格式: 输入包含仅1行,包含两个整数:l.r. 输出格式: 输出仅1行

uestc250windy数数位dp

#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <

USETC 250 windy数 数位DP

注意处理数字只有一位的情况(其实不用怎么处理)= = 简单数位DP #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #

luogu P2657 [SCOI2009]windy数 数位dp 记忆化搜索

题目链接 luogu P2657 [SCOI2009]windy数 题解 我有了一种所有数位dp都能用记忆话搜索水的错觉 代码 #include<cstdio> #include<algorithm> inline int read() { int x = 0,f = 1; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c <= '9' && c >= '

bzoj1026: [SCOI2009]windy数 数位dp

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=1026 题意: Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数 思路: 数位dp,记忆化搜索. 1 #include <bits/stdc++.h> 2 3 using namesp

【BZOJ-1026】windy数 数位DP

1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5230  Solved: 2353[Submit][Status][Discuss] Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数 Sample I

[BZOJ 1026][SCOI 2009]windy数(数位DP)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1026 很基础的数位DP题,很早之前我就尝试做这题,不过当时我被这题吓死了,现在回过头做这题,感觉简单多了. 做这个题时我想到了POJ一道类似的组合数学的题,同样是按数位统计,有异曲同工之妙. 题目要求[a,b]区间上的windy数个数,我们可以转化成求[1,a]上的windy数个数-[1,b-1]上的windy数个数.题目转化成了求[1,x]上的windy数个数,我们就写个函数c

【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP

[BZOJ1662][Usaco2006 Nov]Round Numbers 圆环数 Description 正如你所知,奶牛们没有手指以至于不能玩"石头剪刀布"来任意地决定例如谁先挤奶的顺序.她们甚至也不能通过仍硬币的方式. 所以她们通过"round number"竞赛的方式.第一头牛选取一个整数,小于20亿.第二头牛也这样选取一个整数.如果这两个数都是 "round numbers",那么第一头牛获胜,否则第二头牛获胜. 如果一个正整数N的二

bzoj 1026 [SCOI2009]windy数 数位dp

1026: [SCOI2009]windy数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1026 Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数.