【题目链接】
【思路要点】
- 考虑计算 2 2 2 号操作不超过 i i i 次的方案数。
- 它应当等于 2 2 2 个 k 0 k^0 k0 的倍数、 1 1 1 个 k 1 k^1 k1 的倍数、 1 1 1 个 k 2 k^2 k2 的倍数、……、 1 1 1 个 k i k^i ki 的倍数总和为 N N N 的方案数,从高位向低位 d p dp dp ,那么第 j j j 位可以填数的位置数应当为 m i n { i , j } + 2 min\{i,j\}+2 min{ i,j}+2 ,保留余数不超过 ( i + 2 ) k (i+2)k (i+2)k 的状态即可。
- 上述做法需要进行 O ( L o g N ) O(LogN) O(LogN) 次 d p dp dp ,但压位后已经可以通过。
- 注意到 m i n { i , j } + 2 min\{i,j\}+2 min{ i,j}+2 在 j j j 较小时只与 j j j 有关, j j j 较大时的 d p dp dp 值就是隔板法形成的组合数,可以避免进行 O ( L o g N ) O(LogN) O(LogN) 次 d p dp dp ,改为从低位向高位进行一次 d p dp dp 。
- 不计高精度运算的时间复杂度为 O ( K 2 L o g 3 N ) O(K^2Log^3N) O(K2Log3N) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 55; const int MAXNK = 605; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) { x = max(x, y); } template <typename T> void chkmin(T &x, T y) { x = min(x, y); } template <typename T> void read(T &x) {