P2657 [SCOI2009] windy 数

在这里插入图片描述
依然按照数位dp的套路,利用前缀和思想,先求 f ( a ) : 0 到 a 的 w i n d y 数 f(a):0到a的windy数 f(a):0awindy
状态为 d p ( c u r , t o p ) dp(cur,top) dp(cur,top)表示当前选到 c u r cur cur位,是否贴着上界 t o p top top
然而这种状态表示存在两个问题:
1.当前选择 c u r cur cur位的数字的时候,会被上一个选择的数字是什么限制.
比如上一位选的数字是 1 1 1,那么 2 , 0 2,0 2,0这两个数字就不能选择.需要新增一个状态维度 p r e pre pre,表示上一个数字是 p r e pre pre
2.前导0的问题
比如说 0063 0063 0063,事实上只算作 63 63 63
而如果不考虑该状态,会有一些选了0063的状态被重复选择,所以需要这个状态来避免重复计算
综上,有四个状态 d p ( c u r , p r e , t o p , s t ) : 选到了第 c u r 个数字 , 前一个数字是 p r e , 是否贴着上界 , 是否前边全部是 0 ( 前导 0 状态 ) dp(cur,pre,top,st):选到了第cur个数字,前一个数字是pre,是否贴着上界,是否前边全部是0(前导0状态) dp(cur,pre,top,st):选到了第cur个数字,前一个数字是pre,是否贴着上界,是否前边全部是0(前导0状态)

/*
I don't wanna be left behind,Distance was a friend of mine.
Catching breath in a web of lies,I've spent most of my life.
Catching my breath letting it go turning my cheek for the sake of this show
Now that you know this is my life I won't be told what's supposed to be right
Catch my breath no one can hold me back I ain't got time for that.
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 20;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
int dp[maxn][maxn][2][2];
int a[maxn];
int len = 0;
int dfs(int cur,int pre,bool top,bool st){
	if(!cur) return 1;
	int &ans = dp[cur][pre][top][st];
	if(ans!=-1) return ans;
	ans = 0;
	int bound = top ? a[cur] : 9; 
	for(int i=0;i<=bound;i++){
		if((abs(i-pre)>=2)||(st==1)){
			ans+=dfs(cur-1,i,top&&i==bound,st&&(i==0));
		}  
	}
	return ans;
}
int solve(int n){
	len = 0;memset(dp,-1,sizeof(dp));
	while(n) a[++len] = n%10,n/=10;
	return dfs(len,11,1,1);
}
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int a,b;cin>>a>>b;
	cout<<(solve(b)-solve(a-1))<<"\n";
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值