1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 auto solve = [&] { int a, b, x, y; cin >> a >> b >> x >> y; if (a == b) { cout << 0 << endl; } else if (b == a - 1 && (a & 1 )) { cout << y << endl; } else if (b < a) { cout << -1 << endl; } else { int res = 0 ; for (int i = a; i < b; i++) { if (i & 1 ) { res += x; } else { res += min (y, x); } } cout << res << endl; } };
记x = max { a i } x = \max\lbrace a_{i} \rbrace x = max { a i } ,须满足x − ( ∑ a i − x ) ⩽ dist ( p , q ) ⩽ ∑ a i x - \left(\sum a_{i} - x \right) \leqslant \operatorname{dist}(p,q) \leqslant \sum a_{i} x − ( ∑ a i − x ) ⩽ d i s t ( p , q ) ⩽ ∑ a i 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 auto solve = [&] { int n; cin >> n; ll x1, x2, y1, y2; cin >> x1 >> y1 >> x2 >> y2; ll d2 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); vector<int > a (n) ; for (int i = 0 ; i < n; i++) { cin >> a[i]; } ll r = accumulate (a.begin (), a.end (), 0ll ); ll l = max (0ll , 2 * *max_element (a.begin (), a.end ()) - r); if (l * l <= d2 && d2 <= r * r) { cout << "Yes" << endl; } else { cout << "No" << endl; } };
对于偶数,取前n − 2 n-2 n − 2 个为ℓ \ell ℓ ,后两个为比ℓ \ell ℓ 大,且满足x & ℓ = 0 x\operatorname{\&}\ell=0 x & ℓ = 0 的最小的x x x ,即x = 2 ⋅ 2 highbit ( ℓ ) x=2\cdot 2^{\operatorname{highbit}(\ell)} x = 2 ⋅ 2 h i g h b i t ( ℓ ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 auto solve = [&] { ll n, l, r, k; cin >> n >> l >> r >> k; if (n & 1 ) { cout << l << endl; } else { if (n == 2 || __lg(l) + 1 > __lg(r)) { cout << -1 << endl; } else if (k <= n - 2 ) { cout << l << endl; } else { cout << (2ll << __lg(l)) << endl; } } };
转化为求:对于一个确定的移除 token 的方式,求有多少种序列合法。
DP,设h i j h_{ij} h i j 表示:
转移:
h i j ← i ⋅ ( j − i + 1 ) ⋅ h k , j − 1 , k < i ⩽ j h_{ij} \leftarrow i \cdot (j-i+1) \cdot h_{k,j-1} , \quad k<i \leqslant j h i j ← i ⋅ ( j − i + 1 ) ⋅ h k , j − 1 , k < i ⩽ j
确定移除 tokeni i i 在哪一次操作。设第t t t 次操作移除 tokeni i i 。在规模为j j j 的子问题中,操作t t t 的范围是1 , 2 , … , j 1,2,\dots,j 1 , 2 , … , j 。而且为了移除的 tokeni i i ,依题意必须满足a t ⩽ i ⩽ t a_{t} \leqslant i \leqslant t a t ⩽ i ⩽ t 。所以t t t 的可选择范围是[ i , j ] [i,j] [ i , j ] ,乘上系数j − i + 1 j-i+1 j − i + 1 。
确定a t a_{t} a t 的赋值方式。能够完成移除的 tokeni i i 这个操作的a t a_{t} a t 必须满足1 ⩽ a t ⩽ i 1 \leqslant a_t \leqslant i 1 ⩽ a t ⩽ i ,有i i i 种赋值方式。因此乘上系数i i i 。
所求为h ∗ , N h_{*,N} h ∗ , N ,表示问题规模为N N N ,被移除的 token 的最大下标是∗ * ∗ 。
实现时用前缀和(代码里的 f
)优化h k , j − 1 h_{k,j-1} h k , j − 1 ,总复杂度O ( N 2 ) \mathcal{O}(N^{2}) O ( N 2 ) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 auto solve = [&] { int N, M; cin >> N >> M; Z::setmod (M); vector<Z> f (N + 1 , 1 ) ; Z res = 1 ; for (int i = 1 ; i <= N; i++) { for (int j = N; j >= i; j--) { Z tmp = f[j - 1 ] * (j - i + 1 ) * i; f[j] += tmp; if (j == N) { res += tmp; } } } cout << res << endl; };
赛时的想法是,问题等价于任选k k k ,任选1 ⩽ c 1 < c 2 < ⋯ < c k ⩽ N 1 \leqslant c_1<c_2<\dots<c_k \leqslant N 1 ⩽ c 1 < c 2 < ⋯ < c k ⩽ N ,求 sum ofc 1 c 2 . . . c k ( N + 1 − c k ) ( N − c k − 1 ) ( N − 1 − c k − 2 ) … ( N − k + 2 − c 1 ) c_1 c_2 ... c_k (N+1-c_k)(N-c_{k-1})(N-1-c_{k-2})\dots(N-k+2-c_1) c 1 c 2 . . . c k ( N + 1 − c k ) ( N − c k − 1 ) ( N − 1 − c k − 2 ) … ( N − k + 2 − c 1 )
这个转化比较抽象就不讲了。