洛谷P2657 [bzoj1026] windy数

洛谷P2657 [bzoj1026] windy数
嘿 小友的第一篇博客
听说数位dp的初学者应该先写windy数 于是来记录一下:D
传送门 点这里!
dp[i][j][k][l]表示:前i位,最后一位为j,是否含前导零,是否压上界 的方案数
赋初值为dp[0][0][1][1]=1
怎样求一个区间内所有的windy数呢?可以联想到用前缀和的方法
输入区间[a,b]
于是用solve(b)-solve(a-1)求出答案,因为所求为闭区间,如果是开区间则是solve(b+1)-solve(a)
在solve函数里,枚举数的长度、最低位的数值、是否压上界(比如说原数位123,12x则为压上界,因为不能选择130)、是否有前导零

具体内容详见代码(在此感谢yyr学长)

#include<bits/stdc++.h>
using namespace std;
int num[12], len, dp[12][12][2][2] ;
//dp[i][j][k][l] 表示前i位,最后一位为j,是否含前导零,是否压上界 的方案数
void init(int x)
{
memset(dp,0,sizeof(dp)) ;
len=0 ;
while(x) num[++len]=x%10 , x/=10 ;//倒着统计数的每一位
reverse(num+1, num+len+1) ;//倒置
}
int solve(int up)
{
init(up) ;
dp[0][0][1][1]=1 ;//初值
for(int i=0;i<len;++i) //枚举每一位
for(int j=0;j<10;++j) //枚举上一位的每一个数
for(int k=0;k<2;++k) //是否含前导零
for(int l=0;l<2;++l)//是否压上界
{
int maxt;
if(l) maxt=num[i+1];//若压上界就不能到最大, 有限制
else maxt=9;
for(int t=0;t<=maxt;++t)//这一位可以取的最大值
{
int k2 = (k && !t) ;//上一个数有前导0,并且这位数的t还为0就说明有前导0
int l2 = (l && t==num[i+1]) ; //上一次就压了上界,这一次又压上界
if(k || abs(t-j)>=2)
dp[i+1][t][k2][l2] += dp[i][j][k][l] ;//是前导0或者>=2的条件满足
}
}
int tot=0 ;
//加入所有状态
for(int j=0;j<10;++j)
for(int k=0;k<2;++k) //有前导0也算作状态
for(int l=0;l<2;++l)
tot+=dp[len][j][k][l] ;
return tot;
}
int main(){
int a, b;
scanf("%d%d",&a,&b) ;
printf("%d\n",solve(b) - solve(a-1)) ;
return 0 ;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值