P2657 [SCOI2009]windy数 数位dp
数位dp之前完全没接触过,所以NOIP之前搞一下。数位dp就是一种dp,emm……用来求解区间[L,R]内满足某个性质的数的个数,且这个性质与数的大小无关。
在这道题中,dp[i][j]代表考虑了i位前一位为j,然后进行转移就好。主要是需要考虑前导零和前一位是否为极限。
题干:
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数? 输入输出格式 输入格式: 包含两个整数,A B。 输出格式: 一个整数 输入输出样例 输入样例#1: 复制 1 10 输出样例#1: 复制 9 输入样例#2: 复制 25 50 输出样例#2: 复制 20
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(register int i = a;i <= n;i++) #define lv(i,a,n) for(register int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } int dp[15][15],num[15],a,b; int dfs(int len,int lst,bool sx,bool qd) { if(len == 0) return 1; if(!qd && !sx && dp[len][lst] != -1) { return dp[len][lst]; } int p,cnt = 0,maxx = (sx ? num[len] : 9); for(int i = 0;i <= maxx;i++) { if(abs(i - lst) < 2) continue; p = i; if(qd && i == 0) p = -233; cnt += dfs(len - 1,p,sx && (i == maxx),(p == -233)); } if(!sx && !qd) dp[len][lst] = cnt; return cnt; } int solve(int x) { int k = 0; while(x) { num[++k] = x % 10; x /= 10; } memset(dp,-1,sizeof(dp)); return dfs(k,-233,true,true); } int main() { read(a);read(b); printf("%d\n",solve(b) - solve(a - 1)); return 0; }
只想找一个不会伤害我的人