[BZOJ1026][SCOI2009]windy数 && 数位DP

46 篇文章 0 订阅

不允许前导0的存在 所以先把首位非0的都统计出来 然后在把首位填上非0的数 后面的数就可以自由选择了

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 15;
int d[MAXN+10][MAXN+10], Cur[MAXN+10];
inline int abs(int x) { return x < 0 ? -x : x; }
void init()
{
	for(int i = 0; i <= 9; i++) d[1][i] = 1;
	for(int i = 2; i <= MAXN; i++)
		for(int j = 0; j <= 9; j++)
			for(int k = 0; k <= 9; k++)
				if(abs(j-k) >= 2)
					d[i][j] += d[i-1][k];
}
int solve(int x)
{
	int Len = 0, ans = 0;
	memset(Cur, 0, sizeof(Cur));
	while(x) {
		Cur[++Len] = x % 10;
		x /= 10;
	}
	for(int i = 1; i <= Len-1; i++)
		for(int j = 1; j <= 9; j++)
			ans += d[i][j];
	for(int i = 1; i < Cur[Len]; i++) ans += d[Len][i];
	for(int i = Len-1; i >= 1; i--)
	{
		for(int j = 0; j < Cur[i]; j++)
			if(abs(j - Cur[i+1]) >= 2)
				ans += d[i][j];
		if(abs(Cur[i] - Cur[i+1]) < 2) break;
	}
	return ans;
}
int main()
{
	int L, R;
	init();
	scanf("%d%d", &L, &R);
	int ans = solve(R+1) - solve(L);
	printf("%d", ans);
}

记忆化搜索版

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
using namespace std;
typedef long long LL;
const int MAXN = 15;
int d[MAXN+10][MAXN+10], bit[MAXN+10], tot[MAXN+10];
int f[MAXN+10][MAXN][2][2];
int R, L;
int div(LL x) {
	int len = 0;
	while(x) {
		bit[++len] = x % 10; x /= 10;
	}
	return len;
}
int dp(int cur, int x, bool lim, bool fir) {
	if(cur == 0) return 1;
	if(f[cur][x][lim][fir]) return f[cur][x][lim][fir];
	int ret = 0, ed = lim ? bit[cur] : 9;
	for(int i = 0; i <= ed; i++) {
		if(!fir && abs(i-x) < 2) continue;
		ret += dp(cur-1, i, lim && i==ed, fir&&i==0);
	}
	return f[cur][x][lim][fir] = ret;
}
int main() {
	SF("%d%d", &L, &R);
	int len = div(R), ans = 0;
	ans += dp(len, 0, true, true);
	len = div(L-1);
	ans -= dp(len, 0, true, true);
	PF("%d", ans);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值