T1
Statement
任意相邻两个数字之差至少为 2 的正整数被称为 windy 数。给出 A,B(A≤B≤2×109),求 [A..B] 中有多少个 windy 数。
Solution
我们使用记忆化搜索实现。
f(i,x,a,b) 表示还有 i 位需要确定,上一位数字为 x,是否达到上限,是否不含前导 0 的方案数。
转移:
| int mx = a ? num[i] : 9, ans = 0; |
| for (int k = 0; k <= mx; k++) |
| if (abs(x - k) >= 2 || !b) |
| ans += dfs(i - 1, k, a&(k==mx), b|(k!=0)); |
| f[i][x][a][b] = ans; |
初值:-1
边界:i = 0
时返回 1
答案:dfs(n, 0, 1, 0)
最后用两个前缀相减得到答案。
T2
Statement
给定正整数 A(≤101000)和 S(≤5000),需要在 A 的数码之间添加若干个加号,使得得到的式子与 S 相等。问最少添加多少个加号。
Solution
- num(i,j) 表示 A 中第 i 个数字到第 j 个数字组成的数.
- n 表示 A 的长度,m 表示 S 的长度.
f(i,j) 表示后 i 位数字加起来等于 j 的最少加号数.
f(i,j)=minmin(n,i+2m−1)k=i+1{f(k,j−num(i,k−1))+1}
这里我们让新增的数的位数不超过 S,保证了复杂度;同时注意 j−num(i,k−1) 需要大于 0.
注意到前导零的存在(如 1 + 0001 + 1
),所以我们最多保留 m−1 个连续的 0
,并让 k 循环到 i+2m−1
因为如果有多于 m−1 个连续的 0
,那么多出的 0
就不能与前面的数组合,就没用了;此时 k 最多需要循环到 i+2m−1
初始 f(n,0)=0,其余设为 inf
时间复杂度 O(nmS).
T3
Statement
找一个数作为“支点”,两边的“力矩”相等的数称为“平衡数”。给出正整数 x,y(x≤y≤1018),问 [x..y] 中有多少个“平衡数”。
Solution
由于两边力矩相等,令一边为正、一边为负,那么相加就是 0.
然后发现力矩最大为 18×9+17×9+..+1×9=1539,很小
无限制:
f(x,i,1/0) 表示 i 个数使得力矩为 x 的方案数,每个数 ∈[0,9],其中第一个数能否为 0.
f(x,i,0)=∑9j=0f(x−ij,i−1,0),其中要求 x−ij≥0
f(x,i,1)=∑9j=1f(x−ij,i−1,0)
设这个数有 i 位,则方案数 =∑1539k=0∑i−1j=210×f(k,j−1,1)×f(k,i−j,0)
i=1 时方案数 =10
有限制:
设有 i 位待确定,这个数一共 n 位,每位数字分别为 ak
枚举支点 x 和力矩 y
方案数 =∑n−1x=2∑p+9×max(0,(x−n+i)⋅(x−n+i+1)/2)y=pf(y−p,x−n+i,0)⋅f(y,n−x,0)
其中 p 表示已知的数字在支点 x 下产生的力矩大小,即
p=∑n−i+1j=1aj⋅|x−j|
若 x−n+i≤0,令 f(y−p,x−n+i,0)=1
=======
答案加起来就行了
时间复杂度 O(18×1539+18×1539×18+18×18×1539)=O(1,024,974)
T4
Statement
cnt1(i) 表示二进制整数 i 中包含的数字 1
的个数。给定 N(≤1015),求 ∏Ni=1cnt1(i)modQ。
Solution
不卡到上限:
设有 i 位,选出 j 个 1,则 cnt1=j,有 (ij) 种选法,故乘 (ij) 次
所以 Ans=∏ij=1j(ij)modQ
卡到上限:
设共 L 位,还有 i 位未确定(不包括当前),cnt(k) 表示前 k 位的 1 的数量
若当前已经卡到了上限,则继续向下一位计算(若选 1 则一定会卡到上限);
若当前选 0,则相似地,Ans=∏ij=1(cnt(L−i−1)+j)(ij)modQ
========
所有的 Ans 乘起来再 mod Q 即可,因为只有 15 位,直接暴力算都绰绰有余
我们发现一个问题:(ij) 可能会超过 long long 范围,此时将他 mod φ(Q) 即可
T5
Statement
一个数各相邻数位的下降、相等和上升用 \-/
三个字符表示,然后将连续相同的字符缩写成一个,形成一个长度为 n(≤100)的给定字符串,问 [A..B] 中有多少个数的波动关系缩写以后等于它。0≤A≤B≤10100,有 100 组数据。
Solution
数的长度限制为 m,cmp(x,y) 表示数 x,y 之间的波动关系,ck 表示字符串从右往左第 k 位的波动关系,ak 表示该数从左往右第 k 个数码
f(i,x,j) 表示有 i 位,最高位为 x,对应给出字符串从右往左 j 个字符,的方案数
f(i,x,j)=∑9y=0t,其中 j≠0
当 cmp(x,y)=cj 且 i>j+1 时,t=f(i−1,y,j−1)+f(i−1,y,j)
当 cmp(x,y)=cj 且 i=j+1 时,t=f(i−1,y,j−1)
f(1,x,0)=1,i∈[1,9],其余初始为 0
无限制:Ans=∑m−1i=1∑9j=1f(i,j,n)
有限制:
g(i) 表示确定的前 i 位满足字符串从左往右的字符数,c 变成从左往右数.
i=0 时 Ans=∑ai+1−1j=1f(m,j,n)
i=1 时 Ans=∑ai+1−1j=0 且 cmp(ai,j)=c1f(m−i,j,n−1)+f(m−i,j,n)
i>1 且 g(i)>0 时,其中 j∈[0..ai+1−1]
-
cmp(j,ai)=cg(i) 时:Ans=∑f(m−i,j,n−cg(i)+1)+f(m−i,j,n−cg(i))
-
cmp(j,ai)=cg(i)+1 时:Ans=∑f(m−i,j,n−cg(i)−1)+f(m−i,j,n−cg(i))
最后答案就是加起来. 然后前缀和相减.
复杂度 O(TnmB2),其中 B=10.
T6
Statement
一个数是“漂亮的”,当且仅当它能够被它的每个非零位整除。问 [L..R] 中有多少个数是“漂亮的”。1≤L≤R≤9×1018。
Solution
每个数位 ∈[0,9],观察到 lcm(1,2,..,9)=2520 极小,故枚举 lcm.
那么若一个数被 lcm 整除,则这个数是“漂亮的”.
f(i,j,k) 表示这个数有 i 位(含前导零),这个数 mod 2520=j,这个数的各数位 lcm=k,的个数
假设当前 f(i,j,k) 已知,规定 lcm(x,0)=x,我们用它向外更新:
f(i+1,(j+p)mod2520,lcm(k,p)) += f(i,j,k),其中 p∈[0..9]
f(1,p,p)=1(p∈[0..9]),其余初始化为 0.
无限制:设 n 位,一起算:Ans=∑2520k=1∑⌊2520k⌋l=1f(n,l⋅k,k)
有限制:
设共 n 位,有 i 位已知,s(k) 表示前 k 位已知数码组成的数,l(k) 表示前 k 位已知数码的 lcm.
分开算:Ans=∑2519j=0∑2520k=1f(n−i,j,k),且 j,k 满足 lcm[l(i),k] 整除 [s(i)×10n−i+j]mod2520.
总的答案就把所有 Ans 加起来,然后用前缀和相减得到.
时间复杂度 O(nm2+mlogm+nm2)=O(nm2),其中 n 是数字长度,m=2520.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步