[数位dp] hdu 3886 Final Kichiku “Lanlanshu”

题意:

在范围内满足所给的运算符的数有多少个。

“/” 代表前面的比后面的小 “-”代表前面和后面一样 “\” 代表前面的比后面的大

测试过会出现重复的符号 比如 "///\"

思路:

细心啊细心啊。。!!

数位dp,按位dp

注意几个点就好了:

1、n个运算符至少要有n+1个数。

2、注意开始的状态,第一个数以及第一个运算符。

3、运算符后移注意移动到结束标识就直接返回0。

4、运算符能往后移就往后移。

5、注意大数减一的计算。

6、注意减法的取模。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
//2014年9月26日12:49:21
__int64 dp[102][102][12];
int num[102],m=100000000;  //因为8位数 所以对100000000取模
char v[102];
int ok(int n,int y,int z)
{
    if(n>=101) //特判101
    {
        if(n==101) n=0;
        else return 0;
    }
    if(v[n]=='\0') return 0; //注意如果字符串结束了 返回0
    char x=v[n];
    if(x=='/') return y<z;
    else if(x=='-') return y==z;
    else return y>z;
}
__int64 dfs(int site,int n,int cur,int zero,int f)  //位数,运算符,前一个数,前导零,是否是边界
{
    if(site==0)
    {
        if(zero) return 0;
        int tep=strlen(v)-1;  //是否取到了最后一位
        return tep==n;
    }
    if(!f&&!zero&&~dp[site][n][cur]) return dp[site][n][cur];
    int len=f?num[site]:9;
    int ans=0;
    for(int i=0; i<=len; i++)
    {
        if(zero)
        {
            if(i==0) ans+=dfs(site-1,n,cur,zero&&i==0,f&&i==len);
            else
            {
                if(cur==10) ans+=dfs(site-1,101,i,zero&&i==0,f&&i==len);  //首先第一位直接放进去 然后因为只有一个数还不能确定运算符
                else
                {
                    if(ok(n+1,cur,i)) ans+=dfs(site-1,n+1,i,zero&&i==0,f&&i==len);  //这里的原则是运算符能往后走就往后走
                    else if(ok(n,cur,i)) ans+=dfs(site-1,n==101?0:n,i,zero&&i==0,f&&i==len); //保持原样,然后就是101代表第二个数 因为-1会越界
                }
            }
        }
        else
        {
            if(cur==10) ans+=dfs(site-1,101,i,zero&&i==0,f&&i==len);
            else
            {
                if(ok(n+1,cur,i)) ans+=dfs(site-1,n+1,i,zero&&i==0,f&&i==len);
                else if(ok(n,cur,i)) ans+=dfs(site-1,n==101?0:n,i,zero&&i==0,f&&i==len);
            }
        }
        ans%=m;
    }
    if(!f&&!zero) dp[site][n][cur]=ans;
    return ans;
}
__int64 solve(char *x,int f)  //f用来区分是否要减一
{
    int i=0,cnt=0;
    int len=strlen(x);
    while(x[i]=='0') i++;  //去前导0
    if(x[i]=='\0')  return 0;  //如果是0
    for(int j=len-1; j>=i; j--) num[++cnt]=x[j]-'0'; //放入num
    if(f) //减一
    {
        num[1]--;
        for(int j=1; j<=cnt; j++)
        {
            if(num[j]<0)
            {
                num[j]+=10;
                num[j+1]--;
            }
        }
    }
    if(num[cnt]==0) cnt--; //注意退位
    return dfs(cnt,101,10,1,1);
}
int main()
{
    while(scanf("%s",v)!=-1)
    {
        memset(dp,-1,sizeof(dp));
        char x[123],y[123];
        scanf("%s%s",x,y);  //比较长 要用字符串读入
        printf("%08I64d\n",(solve(y,0)-solve(x,1)+m)%m); //减法一定注意取模。。
    }
    return 0;
}
//2014年9月26日19:08:24
时间: 2024-10-22 02:35:02

[数位dp] hdu 3886 Final Kichiku “Lanlanshu”的相关文章

hdu 3886 Final Kichiku “Lanlanshu” (数位dp)

http://acm.hdu.edu.cn/showproblem.php?pid=3886 给出一个字符,只含'/','-' ,'\' ,表示着一个数上的各位数字按相应字符上升,不变或下降,问[a,b]区间内这样的数有多少个? 数组很好设,dp[i][j][k]表示处理到第i位,它对应的字符是第j位,它前面的数字是k的种类数. 令我纠结好久的是,我起初设的dp[i][j][k]表示处理到第i位时,它的上一位对应的字符是第j位,它的上一位数字是k的种类数,这样可能会导致一个'/'只有一个数字,但

[数位dp] hdu 3967 Zero&#39;s Numberd

题意:对于两个数i和k,把它分为两个部分的数,n和m,如果(n+m)%k=0 那么这算一种分法 比如 333可分成,3.33或者33.3,对于 (333,3)就等于2. 现在给出 a.b.k,为 (a~b,k)有多少种分法 思路:对于一个数,注意前导零并枚举分点就好了. dp[22][22][22][22][2],   代表 i位,分点为fd,余数mod,对于k取余,是否有前导零 代码: #include"cstdlib" #include"cstdio" #inc

【HDOJ】3386 Final Kichiku “Lanlanshu”

数位DP.需要注意的是需要特殊处理前导0,另外连续的==匹配,不要计重了,尽量贪心的匹配掉. 1 /* 3886 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vec

浅谈数位dp——hdu 不要62

HDU-------不要62 题目传送门 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) 问题描述: 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众.不吉利的数字为所有含有4或62的号码.例如:62315 73

数位dp HDU - 5898 odd-even number

http://acm.hdu.edu.cn/showproblem.php?pid=5898 题意:求两个数中间的满足连续位是奇数的长度是偶数,连续位上是偶数的长度位奇数的数量. 分析:就是数位dp基本写法,dfs 的参数多加了个 a 表示连续位数的长度,flag表示上一位是否为奇数.  这里当奇偶改变时,a 就要变成1 ,并且可以用 a=0 来表示区分是前导0 .然后 记忆化搜索的过程中 ,用continue 表示不满足条件,暂时满足才往下接着搜索. 然后!!     &运算的优先程度比 ==

2019年9月训练(壹)数位DP (HDU 2089)

开学之后完全没时间写博客.... HDU 2089 不要62(vjudge) 数位DP 思路: 题目给出区间[n,m] ,找出不含4或62的数的个数 用一个简单的差分:先求0~m+1的个数,再减去0~n的个数. 但问题依旧不简单,再次简化为求0~i位数中不含4或62的数的个数. i=1 //0~9中 i=2 //0~99中 i=3 //0~999中 ...... dp[i][0] //0~i位数中的吉利数 dp[i][1] //0~i位数中以2打头的吉利数 dp[i][2] //0~i位数中的非

[数位dp] hdu 3271 SNIBB

题意:有两种询问: q=1,在[x,y]区间内,转换成b进制数,数位和为m的有多少个. q=2,在[x,y]区间内,转换成b进制数,数位和是m的第k个数是多少(十进制),不存在按题目给出输出. 思路: 和普通数位dp一样,第几个数的话就是二分判断. 然后就是按常理要开4维,就是dp[i][sum][b][m] i位,和为sum,b进制,最后和为m 但是开不下,所以开3维每次初始化. 注意一下: 1.每次都要初始化 2.x不一定小于y 3.是[x,y]不是(x,y] 代码: #include"cs

数位DP [HDU 3652] B-number

B-number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2668    Accepted Submission(s): 1467 Problem Description A wqb-number, or B-number for short, is a non-negative integer whose decimal fo

Final Kichiku “Lanlanshu”

题目链接 题意: 至今也没看懂题目叙述...弱菜,看别人程序看懂题意得... 给一串字符串,包含'/'  '\'    '-'三种,分别表示下一个数比当前大,小,相等.要求出[a, b]区间内,满足要求的数有多少个:要求是,将字符串分成若干段,每段的符号均相同.再将数字也分成若干段,那么数字每一段与字符串的每一段对应,且数字段内相邻数的上升.下降.相等关系应满足对应字符串的符号关系,且每段数字段的数字个数应该大于等于对应符号段的符号个数. 分析: 数位DP解决时,状态为[pos][idx][pr