1 条题解
-
0
自动搬运
来自洛谷,原作者为

jianhe
以颤抖之身追赶,怀敬畏之心挑战。--《棋魂》|| 最后在线时间:2025年8月23日22时4分搬运于
2025-08-24 23:07:24,当前版本为作者最后更新于2024-12-24 19:45:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
前言:
MnZn 第一次打 USACO,降智降到用数位 dp 过了这个题。
喜提洛谷最劣解。
有一说一在理解数位 dp 的前提下还是非常好懂(doge)。
题意:
求在 中 逐位四舍五入 和 直接四舍五入 不同的数的个数。
思路:
首先逐位四舍五入肯定不小于直接四舍五入。
容易发现,如果想要两者不同的话,只能是逐位四舍五入多进了一些位。
怎么样才能达到呢?只有一串 后面跟上 的数才行。
数位 dp 即可。判当前的有效位数并记录是否填过 的数,按照一串 后跟一个 来填,后面的数随便填就可以了。
代码里有详细注释。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const ll N=11; ll T,n,dp[N][N][2]; vector<ll> p; ll dfs(ll x,bool up,bool z,ll wei,bool wu){ // x 表示位数(从大到小),up 表示当前是否取满(即当前位是能取到 9 还是只能取到 p[x]) // z 表示是否有前导零,wei 表示当前有效位的位数(即去除前导零),wu 表示是否存在 4...4 (>=5) if(!~x) return wu; if(!up&&!z&&~dp[x][wei][wu]) return dp[x][wei][wu];// 记忆化 ll ct=0;// 答案 if(!wei) ct+=dfs(x-1,0,1,0,0);// 前导零特判 for(int i=0;i<=(up?p[x]:9);i++) if((!wei&&i==4)||(wei>=1&&!wu&&i>=4)||wu) ct+=dfs(x-1,up&&i==p[x],z&&(!i),wei+1,wu|(i>=5)); // !wei&&i==4 :第一位填 1 // wei>=1&&!wu&&i>=4 :一串 4 后面填 >=5 的数 // wu :前面已经满足条件了,这位可以随便填(只要在范围内) // up&&i==p[x] :下一位是否取满 // z&&(!i) :下一位是否还都是前导零 // wei+1 :有效位 +1 // wu|(i>=5):是否存在 4...4 (>=5) if(!up&&!z) dp[x][wei][wu]=ct;// 记忆化 return ct; } ll C(ll n){// 将 n 拆成一位一位 p.clear(); while(n) p.push_back(n%10),n/=10;// 十进制拆分 return p.size()-1; } ll solve(ll n){memset(dp,-1,sizeof dp);return dfs(C(n),1,1,0,0);} int main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>T;while(T--) cin>>n,cout<<solve(n)<<"\n"; return 0; }
- 1
信息
- ID
- 11153
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者