正睿 NOIP2023 20连 Day4 T3 题解

Description

称一个正整数对 (a,b)(a, b) 合法,当且仅当存在正整数 kk 和 kk 组正整数对 (h1,w1),(h2,w2),⋯ ,(hk,wk)(h_1, w_1), (h_2, w_2), \cdots, (h_k, w_k),使得:

  • ∑i=1khiwi=a\sum_{i = 1} ^ k h_iw_i = a。
  • ∑i=1k2(hi+wi)=b\sum_{i = 1} ^ k 2(h_i + w_i) = b。

给定 s,cs, c,求满足 a∈[1,s],b∈[1,c]a \in [1, s], b \in [1, c] 的正整数对中有多少是合法的。

对于 100%100\% 的数据,满足 1≤s≤2×105,1≤c≤4×105,2∣c1 \le s \le 2 \times 10^5, 1 \le c \le 4 \times 10^5, 2 \mid c。

Solution

这里先把 cc 除以 22。

不妨设 hi≤wih_i\leq w_i,易知 hi≤sh_i\leq \sqrt s。

如果存在 hi=hjh_i=h_j,那么 (hi,wi),(hi,wj)(h_i,w_i),(h_i,w_j) 可以修改为 (hi,wi+wj−1),(1,hi)(h_i,w_i+w_j-1),(1,h_i)。

然后 11 的情况也可以消,(1,x),(1,y)(1,x),(1,y) 可以变为 (1,x+y−1),(1,1)(1,x+y-1),(1,1),所以如果把 (1,1)(1,1) 删掉,对于每个 hh,只有唯一的一个 ww 与之对应。

如果把 (1,1)(1,1) 加上,会发现 2a−b2a-b 的值不会变,所以可设 fif_i 表示当前 2a−b=i2a-b=i 的最小的 bb。

然后枚举 h,wh,w,可以得到转移方程:fi←fi−(2hw−h−w)+h+wf_i\leftarrow f_{i-(2hw-h-w)}+h+w。

把底下那玩意拆开,fi←fi+h−w(2h−1)+h+wf_i\leftarrow f_{i+h-w(2h-1)}+h+w。

这样就只要枚举 hh,令 gig_i 表示 j+h−w(2h−1)=ij+h-w(2h-1)=i 的最小的 fj+wf_j+w,那么 gi=min⁡{fi,gi−(2h−1)+1}g_i=\min\{f_i,g_{i-(2h-1)}+1\}。

所以 fi=gi+h+hf_i=g_{i+h}+h。

然后统计答案就枚举那个 2a−b2a-b,不妨设为 ii,bb 要满足 2∣(i+b)2|(i+b) 且 fi≤b≤2n−if_i\leq b\leq 2n-i。

时间复杂度:O(ss)O(s\sqrt s)。

Code

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
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 5e5 + 5;

int n, m;
int f[kMaxN], g[kMaxN];

void dickdreamer() {
std::cin >> n >> m;
m /= 2;
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= n; ++i)
f[i - 1] = i + 1;
for (int h = 2; h * h <= n; ++h) {
std::swap(f, g);
for (int i = 0; i <= 2 * n; ++i)
f[i] = g[i];
g[0] = 0;
for (int i = 0; i <= 2 * n + h; ++i) {
if (i > 2 * n) g[i] = 1e9;
if (i >= 2 * h - 1) g[i] = std::min(g[i], g[i - (2 * h - 1)] + 1);
}
for (int i = 0; i <= 2 * n; ++i)
f[i] = std::min(f[i], g[i + h] + h);
}
int64_t ans = 0;
for (int i = 0; i <= 2 * n; ++i) {
int l = f[i] + ((i + f[i]) & 1), r = std::min(m, 2 * n - i);
if (l <= r) ans += (r - l) / 2 + 1;
}
std::cout << ans << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

正睿 NOIP2023 20连 Day4 T3 题解
https://sobaliuziao.github.io/2023/10/12/post/3f4ab0d1.html
作者
Egg_laying_master
发布于
2023年10月12日
许可协议