概述
2023大厂真题提交网址(含题解):
www.CodeFun2000.com(http://101.43.147.120/)
最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
题目大意:
题目地址
让你求出 [ l , r ] [l,r] [l,r]中满足①数位中不含7的数②数位之和不是7的倍数③数本身不是7的倍数 的所有数的平方和.
题目思路:
这个题算是一个数位dp好题了。他让我对数位dp的过程有了一个更深刻的看法。
其他很简单,难点在于平方和.先将数位映射到树上。
1.以往让我们求区间合法的数的个数 等同于 求树上叶子节点个数
2.现在要求区间 [ 1 , n ] [1,n] [1,n]的每个数的和,如何做?
还是映射到树上。因为我们数位dp的本质就是将每个数按位拆分,而且每个数位状态代表树上一个节点,即任意一个 d p ( i , j , k ) dp(i,j,k) dp(i,j,k)代表以树上该节点为根的子树的答案/贡献.然后考虑转移。
假设某状态 ( i , j ) (i,j) (i,j)代表前i位,是否顶到上界,该节点放置数位 d d d.要求它的贡献。那该颗子树所代表的数的个数即为叶子节点个数.假设为 k k k.再假设这些数是: { x 1 , x 2 , . . . , x k } {x_1,x_2,...,x_k} {x1,x2,...,xk}.转移就是在每个数前面(最高位)要添加一个数位 i i i.那最终答案(dp值)为: ( x 1 + d ∗ 1 0 p ) + ( x 2 + d ∗ 1 0 p ) + . . . + ( x k + d ∗ 1 0 p ) (x_1+d*10^p)+(x_2+d*10^p)+...+(x_k+d*10^p) (x1+d∗10p)+(x2+d∗10p)+...+(xk+d∗10p)。
稍微变形可得: ∑ i = 1 k x i + ∑ i = 1 k d ∗ 1 0 p sum_{i=1}^k x_i+sum_{i=1}^k d*10^p ∑i=1kxi+∑i=1kd∗10p.
前半部分就是下一个阶段的 d p dp dp值,后半部分的 k k k(即合法数的个数,即叶子节点个数)我们需要额外开一个数组 g g g去维护.
3.现在要求区间 [ 1 , n ] [1,n] [1,n]的每个数的平方和,如何做?
分析套路和上面一模一样,假设平方和答案为 f f f数组。那么最终答案为 ( x 1 + d ∗ 1 0 p ) 2 + ( x 2 + d ∗ 1 0 p ) 2 + . . . + ( x k + d ∗ 1 0 p ) 2 (x_1+d*10^p)^2+(x_2+d*10^p)^2+...+(x_k+d*10^p)^2 (x1+d∗10p)2+(x2+d∗10p)2+...+(xk+d∗10p)2
稍微变形可得:
原式
=
∑
i
=
1
k
(
x
i
2
+
d
2
1
0
2
p
+
2
∗
x
i
∗
d
∗
1
0
p
)
原式=sum_{i=1}^k (x_i^2+d^210^{2p}+2*x_i*d*10^p)
原式=∑i=1k(xi2+d2102p+2∗xi∗d∗10p)
=
f
(
i
−
1
)
+
g
(
i
−
1
)
∗
d
2
1
0
2
p
+
2
∗
d
∗
1
0
p
∗
d
p
(
i
−
1
)
=f(i - 1)+g(i-1)*d^210^{2p}+2*d*10^p*dp(i-1)
=f(i−1)+g(i−1)∗d2102p+2∗d∗10p∗dp(i−1)
所以这个部分维护 d p , g , f dp,g,f dp,g,f分别代表合法数的个数,累和,平方和即可.
心得:
分析数位dp问题的时候脑子里装一颗树即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vl vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mx = 7;
const int mod = 1e9 + 7;
string xx;
ll p[55] , p2[55];
struct Node
{
ll num , sum , ssum; // 个数 , 和 , 平方和
}dp[20][2][8][8];
Node dfs (int step , int lim , int pre1 , int pre2)
{
if (step == -1) return {pre1 && pre2 , 0 , 0};
Node &x = dp[step][lim][pre1][pre2];
if ( ~x.num ) return x;
int up = lim ? xx[step] - '0' : 9;
Node ans = {0,0,0};
for (ll i = 0 ; i <= up ; i++){
// ① 数位中不能出现7
if (i == 7) continue;
Node tmp = dfs(step - 1 , lim && i == up , (pre1 + i)%mx, (pre2 + i * p2[step]%mx)%mx);
ans.num = (ans.num + tmp.num) % mod;
ans.sum = (ans.sum + tmp.sum) % mod; // 来自子树的贡献
ans.sum = (ans.sum + i * p[step]%mod * tmp.num%mod); // 节点的贡献
// 三个部分
ans.ssum = (ans.ssum + i * i%mod * p[2 * step]%mod * tmp.num %mod)%mod;
ans.ssum = (ans.ssum + tmp.ssum)%mod;
ans.ssum = (ans.ssum + 2 * i % mod * p[step] % mod * tmp.sum %mod)%mod;
}
return x = ans;
}
ll solve (ll x)
{
memset(dp , -1 , sizeof dp);
xx = to_string(x);
reverse(xx.begin() , xx.end());
return dfs(xx.size() - 1 , true , 0 , 0).ssum;
}
int main()
{
ios::sync_with_stdio(false);
int t; cin >> t;
p[0] = p2[0] = 1;
for (int i = 1 ; i <= 50 ; i++){
p[i] = p[i - 1] * 10 % mod;
p2[i] = p2[i - 1] * 10 % mx;
}
while (t--){
ll l , r; cin >> l >> r;
cout << (solve(r) - solve(l - 1) + mod)%mod << endl;
}
return 0;
}
最后
以上就是轻松眼神为你收集整理的数位dp好题-恨7不成妻2023大厂真题提交网址(含题解):的全部内容,希望文章能够帮你解决数位dp好题-恨7不成妻2023大厂真题提交网址(含题解):所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复