把过去和现在的笔记记录也搬了过来,也算是给以后留个念想吧,想想一开始打acm就是图一乐,后来发现这游戏还挺上头的,也算是度过了一段电竞生涯(xs)
早些时候的笔记写的好中二,连我自己看着都羞耻。
不过,就喜欢这种羞耻的感觉。
收录的题目大部分是个人认为质量不错的题目,以DP为主,非DP的题目都用※进行了标识。
当然,有些题解思路本身也是源自其他人的,不过除非特殊标注,否则都是用的自己的代码。

题目大意:

1538F Interesting Function
题目大意:你要把l通过不断加1变成r,求数字改变的次数(9到10这种算是改变两次,99到100三次,以此类推),数字规模为1e9。

解:

首先,为什么说它是数位,因为改变的单位是1,所以从l加到r所需的改变次数等于1到r的次数减去1到l-1的次数,也就是答案是线性的。然后,由于数字发生超过1的改变的时机是在进位的时候,也就是说可以将数位作为可以递推的状态。千万要注意,数位dp并不一定要是10进制,但一定和进制有关,所以,即使是BAString那题我们也可以看作数位dp,不过这是题外话了。
状态非常好做,i为位数,dp[i]=10dp[i-1]+1,数位dp的结果可以使用记忆化dfs。
实际上这题说是数位板子题都嫌太过了,因为根本没有涉及到数位间的复杂联系……

代码

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
#include <istream>
#include <map>
#include <cmath>
#include <stack>
#include <set>
#include <cstring>
#include <string>
#define ll long long
#define maxn 2000002
#define mdl 1000000007
#define clr(a,n) for(int i=0;i<n;i++)a[i]=0
#define cfast std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pll pair<ll,ll>
#define inc(i,a,n) for(int i=a;i<n;i++)
using namespace std;
int dp[10];
int digit[20];
int dfs(int pos, bool fp)
{
if (pos == 0)return 0;
if (fp == 0)return dp[pos];
else {
ll ret = 0;
int fpmx = digit[pos];
inc(i, 0, fpmx) {
ret += dp[pos];
}
ret += dfs(pos - 1, 1);
return ret;
}
}
int cal(int x)
{
int i, len;
len = 0;
while (x) //求出每一位
{
digit[++len] = x % 10;
x /= 10;
}
return dfs(len,1);
}
void init() {
dp[1] = 1;
inc(i, 2, 11) {
dp[i] = dp[i - 1] * 10 + 1;
}
}
int main()
{
cfast;
int t;
cin >> t;
init();
while (t--) {
ll l, r;
cin >> l >> r;
cout << cal(r) - cal(l) << endl;
}
return 0;
}
/*

*/