2 条题解
-
1
这个题的一个解法是数位dp
就是直接统计每个数位的出现频率再乘上本身
同时有一个类似的题
数位dp推荐都写成dfs形式的,因为递推式的数位dp是很难处理边界条件的
刚开始学数位dp我建议把状态全部记上,
比如常见的有第数位,前导零,上下界,
代码如下
#include <bits/stdc++.h> #define int long long using namespace std; int a[20], memo[16][16][2][2]; int dfs(int p,int sm,bool ld,bool lm,int tg) { if (p==0) { return sm; } // 这里的变量名含义,p是目前处理到第几个数位, // sm是当前该数位(也就是tg)一共出现了几次 // ld就是是否含有前导0 // lm就是是否贴着上界 //处理上下界的原因是因为枚举该位的数字 if (memo[p][sm][ld][lm]!=-1) { return memo[p][sm][ld][lm]; } int res=0; int up=lm ? a[p] : 9; //如果是27000,如果最高位不是2,下一位枚举的数字可以是0-9,但是如果最高位是2,下一位枚举的数字只能是0-7 for (int i=0;i<=up;i++) { int nsm=sm+ ((i==tg)&&!(ld && i==0)); //处理前导0的原因是因为数字不含前导0,比如9,如果有前导0计数可能是009,会干扰到0的计数 res+=dfs(p-1,nsm,ld && (i==0),lm && (i==up),tg); //这里如果下一位依然是0并且仍然处于前导0状态仍然记作前导0, // } return memo[p][sm][ld][lm]=res; //返回的时候直接把状态存上 } int sol(int n, int tg) { int len = 0; while (n) a[++len] = n % 10, n /= 10; memset(memo, -1, sizeof(memo)); return dfs(len,0,true,true,tg); } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin>>t; while(t--) { int n; cin>>n; int ans=0; for (int i=0;i<=9;i++) { ans+=sol(n,i)*i; } cout<<ans<<'\n'; } }然后恭喜你收到了一个TLE的代码
因为这个地方的 很大,并且 不受 的约束
所以数位dp时我们不能memset的方式来解决初始化
memset是因为我们我们在处理0-9每个数位以及每组数据之间都要重置一下,
我们可以直接把状态全部存完并且加上vis数组规避memset
#include <bits/stdc++.h> #define int long long using namespace std; int a[20]; int memo[20][20][2][2][10];//加上数位的状态 bool vis[20][20][2][2][10]; int dfs(int p, int sm, bool ld, bool lm, int tg) { if (p == 0) { return sm; } if (vis[p][sm][ld][lm][tg]) { return memo[p][sm][ld][lm][tg]; } int res = 0; int up = lm ? a[p] : 9; for (int i = 0; i <= up; i++) { int nsm = sm + ((i == tg) && !(ld && i == 0)); res += dfs(p - 1, nsm, ld && (i == 0), lm && (i == up), tg); } if (!lm) { vis[p][sm][ld][lm][tg] = true; return memo[p][sm][ld][lm][tg] = res; } return res; } int sol(int n, int tg) { int len = 0; while (n) a[++len] = n % 10, n /= 10; return dfs(len, 0, true, true, tg); } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while(t--) { int n; cin >> n; int ans = 0; for (int i = 0; i <= 9; i++) { ans += sol(n, i) * i; } cout << ans << '\n'; } return 0; }其实数位dp写多了你就能发现这东西其实是轮椅
信息
- ID
- 1166
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- (无)
- 递交数
- 22
- 已通过
- 5
- 上传者