题意:
一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位……)上的数字是奇数,偶数位(十位、千位、十万位……)上的数字是偶数,我们就称之为“好数”。
给定一个正整数 N,请计算从 1 到 N 一共有多少个好数。
思路:
这里不对暴力进行讲解,网上有非常多的题解,做法也很简单,这个做法的缘由是我没看数据量,认错了,以为是数位dp,当时没做出来,现在补上,也算是学习数位dp了
参考题解:P10424 [蓝桥杯 2024 省 B] 好数 数位dp_蓝桥杯好数问题-CSDN博客
原题主里面的cnt--是不必要的,讲错了
思路其实也不难,就是标准的数位dp,这里讲解是怎么来理解这道题的数位dp的
dp[i]表示的是,当前位置之前填写最高位的这个时刻,填剩下所有可能数的大小,往后就是默认填写最高位数字的,如果不是很明白推荐 董晓老师的数位dp
1.dp[i]代表当前这一位在填写[1,3,5,7,9]或者[0,2,4,6,8](注意要小于数本身)的可能算上所有的个数,因为高位固定,低位一定能两个区间都能取的,直接预处理pre数组,进行计算就好。个数就是能填的个数xpre[i],注意不包括本身
2.为什么不包括本身,因为本身是不可直接计算的,因为你计算的话可能超过本身的数。dp那里计算的是一定能得到的所有数,所以最后有一个if,判断最后dp结束的那个数本身。
3.但这并没有结束,因为其实奇数位是能填0的,前提是高位没有任何数,所以加上最后的个数,就是答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N = 2e5+10;
const int INF = 1e18;
const int MOD = 1e9+7;
int pre[20],num[20];
void solve(){
int n;
cin >> n;
pre[1]=1;
for(int i=2;i<20;i++){
pre[i]=pre[i-1]*5;
}
int cntt=1;
while(n){
num[cntt++]=n%10;
n/=10;
}
cntt--;
int sum=0;
for(int i=cntt;i>=0;i--){
int cur=num[i];
if(cur){
int cnt=0;
if(i&1){
cnt+=cur/2;
}
else{
cnt+=(cur+1)/2;
}
sum+=cnt*pre[i];
}
if( (i&1) != (num[i]&1) ){
break;
}
if(i==1 && num[i]&1){
sum++;
}
}
for(int i=cntt;i>1;i--){
if(i&1){
sum+=pre[i];
}
}
cout << sum << endl;
}
signed main() {
IOS;
int t = 1;
// cin >> t;
while (t--) {
solve();
}
}