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的种类数,这样可能会导致一个'/'只有一个数字,但是题目要求是'/'’-‘'\'必须是至少两个相邻的数字满足。
如果把j理解为当前第i位应该对应的是第j个字符,那么只需拿当前取的数字num和k相比是否满足s[j]这种关系,若满足,就继续递归下一个字符,若不满足,就拿num和k相比是否满足s[j-1]关系,如果满足,就继续递归s[j]这种关系。
从这题可以得出结论,设置状态的时候,要针对当前这一位,尽量让当前这一位的选择是确定的。
#include <stdio.h> #include <iostream> #include <map> #include <set> #include <list> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> //#define LL __int64 #define LL long long #define eps 1e-12 #define PI acos(-1.0) using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 4010; const int mod = 1e8; char s[110],a[110],b[110],dig[110]; int slen,alen; int dp[110][110][12]; bool check(int a, int b, char ch) { if(ch == '/') return a < b; else if(ch == '-') return a == b; else return a > b; } int dfs(int len, int pos, int pre, int up, int first) { if(len == alen) { return pos==slen; } if( !up && !first && dp[len][pos][pre] != -1 ) return dp[len][pos][pre]; int n = up ? (dig[len]-'0') : 9; int res = 0; for(int i = 0; i <= n; i++) { if(first) res += dfs(len+1,0,i,up&&i==n,first&&i==0); else { if( pos < slen && check(pre,i,s[pos]) ) res += dfs(len+1,pos+1,i,up&&i==n,0); else if(pos > 0 && check(pre,i,s[pos-1]) ) res += dfs(len+1,pos,i,up&&i==n,0); } res %= mod; } if(!up && !first) dp[len][pos][pre] = res; return res; } int cal(char x[], int f) { memset(dp,-1,sizeof(dp)); alen = strlen(x); int st = 0; while(x[st] == '0') st++; if(st >= alen) return 0; if(f == 1) //处理a-1 { for(int i = alen-1; i >= st; i--) { if(x[i] >= '1') { x[i]--; break; } else { x[i] = '9'; } } } strcpy(dig,x); return dfs(st,0,0,1,1); } int main() { while(~scanf("%s",s)) { slen = strlen(s); scanf("%s %s",a,b); printf("%08d\n",((cal(b,0) - cal(a,1)%mod)+mod)%mod ); } return 0; }