0%

题目大意

题目描述
Gagamboy 需要购买 rr 种不同的化学物质,每种需要 1kg。电商平台上共有 cc 个卖家。
给定一个 r×cr \times c 的价格矩阵 AA,其中 ai,ja_{i,j} 表示从卖家 jj 处购买 1kg 化学物质 ii 的价格。
此外,对于每个卖家 jj,只要从该卖家处购买了任何数量的化学物质(哪怕只有一种),都需要额外支付一笔固定的配送费 djd_j
请计算购买到所有 rr 种化学物质(每种至少 1kg)所需的最小总花费。本题包含多组独立测试数据。

输入格式
第一行包含一个整数 TT1T101 \le T \le 10),表示测试数据的组数。
对于每组测试数据:
第一行包含两个由空格分隔的整数 rrcc1r,c1 \le r, c,且 r×c250r \times c \le 250)。
接下来 rr 行,每行包含 cc 个由空格分隔的整数,第 ii 行的第 jj 个数为 ai,ja_{i,j}1ai,j10151 \le a_{i,j} \le 10^{15})。
最后一行包含 cc 个由空格分隔的整数 d1,d2,,dcd_1, d_2, \dots, d_c1dj10151 \le d_j \le 10^{15}),表示每个卖家的配送费。

输出格式
对于每组测试数据,输出一行一个整数,表示完成购买所需的最小总花费。

样例输入

1
2
3
4
5
6
7
8
9
10
11
12
2
3 5
1 3 5 7 9
5 7 9 1 3
9 1 3 5 7
4 3 2 3 4
4 3
1 2 4
2 3 1
4 1 2
3 2 1
2 4 4

样例输出

1
2
11
11

样例解释
对于第一组样例:
一种最优的购买方案如下:

  • 向卖家 2 购买化学物质 1 和 3。它们的价格分别为 a1,2=3a_{1,2} = 3a3,2=1a_{3,2} = 1。支付这笔订单所需的配送费为 d2=3d_2 = 3

  • 向卖家 4 购买化学物质 2。它的价格为 a2,4=1a_{2,4} = 1。支付这笔订单所需的配送费为 d4=3d_4 = 3
    总花费为:((3+1)+3)+(1+3)=11((3 + 1) + 3) + (1 + 3) = 11

对于第二组样例:
最优方案能达到的最小花费同样为 11。

思路讲解

这道题目的做法,首先,需要想到:绷不住了,这道题目,观察到 chem * sell <= 250,那么,chem,sell 理论上来说,应该不会同时超过 16,因为 16*16=256,这样子,chem 小,就对 chem 进行状态压缩sell 小,就对 sell 进行状态压缩

确实是感觉到,如果不进行状态压缩,那么这道题目非常难做

如果进行状态压缩的话,状态压缩 seller 非常好做。枚举的是给哪些 seller 付了这个运费。

给哪些 seller 付了这个运费,就只能从这些 seller 这里购买化学品。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ll ans=INF;
// 枚举的是给哪些 seller 付了这个运费
for (int s=1;s<(1<<M_j_sell);++s) {
vector<ll> mn_price(N_i_chem+2,INF);
ll offset_j=1;
ll price=0;
// 给哪些 seller 付了这个运费,就只能从这些 seller 这里购买化学品
for (int j=0;j<M_j_sell;++j) {
if (s>>j&1) {
price+=D_j_sell[j+offset_j];
for (int i=1;i<=N_i_chem;++i) {
mn_price[i]=min(mn_price[i],A[i][offset_j+j]);
}
}
}
for (int i=1;i<=N_i_chem;++i) {
price+=mn_price[i];
}
ans=min(ans,price);
// dp[s]=price;
}
cout<<ans<<"\n";

我们来看,状态压缩 chem,我们怎么做?这个会难一点。

我们不难观察到,一个子集 S 的最优解,一定是这样的:把一部分子集交给一个买家,把另一部分子集交给一个买家,把又一部分子集交给又一买家……。

在状态压缩 化学品的时候,我们需要学习一种写法,即枚举 mask 的子集。

1
2
3
4
5
6
for (int S = 0; S < (1 << r); S++) {
for (int T = S; T > 0; T = (T - 1) & S) {
// T 是 S 的非空子集
dp[S] = min(dp[S], dp[S ^ T] + best[T]);
}
}

枚举 mask 的所有子集,是 O(3n)O(3^n)

如果说枚举 seller,允许你去这个枚举子集,是不是会简单一点?

预处理:对每个非空子集 TT,预先算好从所有卖家中买 TT 的最小花费:best(T)的意思就是在包括这个运费的情况下,该 chem 子集 T,从哪一个买家那里采购,所需花费最低

best(T)=minj=1c(dj+iTai,j)\text{best}(T) = \min_{j=1}^{c} \left(d_j + \sum_{i \in T} a_{i,j}\right)

具体而言就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ll offset_i=1;
vector<ll> best((1<<N_i_chem)+2);
for (int s=1;s<(1<<N_i_chem);++s) {
ll lans=INF;
for (int j=1;j<=M_j_sell;++j) {
ll price=D_j_sell[j];
for (int i=0;i<N_i_chem;++i) {
if (s>>i&1) {
price+=A[offset_i+i][j];
}
}
lans=min(lans,price);
}
best[s]=lans;
}

转移方程如下,容易写出:

dp[S]=minTS(dp[ST]+best(T))dp[S] = \min_{\emptyset \neq T \subseteq S} \left(dp[S \setminus T] + \text{best}(T)\right)

你可能会有疑问,这个运费会不会重复算?答案是是的,但是我们肯定不会采用运费重复算的组合

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
vector<ll> dp((1<<N_i_chem)+2);
// for (int j=1;j<=M_j_sell;++j) {
// dp[0][j]=0;
// }
// for (int s=1;s<(1<<N_i_chem);++s) {}
ll offset_i=1;
vector<ll> best((1<<N_i_chem)+2);
for (int s=1;s<(1<<N_i_chem);++s) {
ll lans=INF;
for (int j=1;j<=M_j_sell;++j) {
ll price=D_j_sell[j];
for (int i=0;i<N_i_chem;++i) {
if (s>>i&1) {
price+=A[offset_i+i][j];
}
}
lans=min(lans,price);
}
best[s]=lans;
}
for (int s=1;s<(1<<N_i_chem);++s) {
ll lans=INF;
for (int t=s;t>0;t=(t-1)&s) {
lans=min(lans,dp[s^t]+best[t]);
}
dp[s]=lans;
}
cout<<dp[(1<<N_i_chem)-1]<<"\n";

AC代码

AC
https://codeforces.com/gym/106262/submission/365538444

心路历程(WA,TLE,MLE……)

题目大意

题目描述
给定三个整数 a,b,ca, b, c,每次可以选择执行以下两种操作之一:

  1. aa+ba \leftarrow a + b

  2. aaba \leftarrow a \oplus b\oplus 为按位异或运算)

你可以执行任意次上述操作。请判断最终是否能将 aa 变为 cc

输入格式
第一行为测试数据组数 TT1T1031 \le T \le 10^3)。
接下来 TT 行,每组数据包含三个整数 a,b,ca, b, c0a,c10180 \le a, c \le 10^{18}1b10001 \le b \le 1000)。
保证在一个测试点内 b2106\sum b^2 \le 10^6

输出格式
对于每组数据,如果最终能将 aa 变为 cc,输出 YES,否则输出 NO

样例数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
输入:
5
1 6 7
7 5 13
8 3 16
7 6 17
2 7 8

输出:
YES
NO
YES
YES
NO

样例解释

  • 第一组数据 1 6 7:初始 a=1a=1,执行一次加法操作 1+6=71 + 6 = 7,即可得到 c=7c=7,输出 YES

  • 第二组数据 7 5 13:无法通过进行 +5+55\oplus 5 操作从 77 得到 1313,输出 NO

  • 第三组数据 8 3 16:初始 a=8a=8,执行路线可为:
    8311+314313+3168 \xrightarrow{\oplus 3} 11 \xrightarrow{+3} 14 \xrightarrow{\oplus 3} 13 \xrightarrow{+3} 16,最终得到 c=16c=16,输出 YES

  • 第四组数据 7 6 17:初始 a=7a=7,执行路线可为:
    7+613611+6177 \xrightarrow{+6} 13 \xrightarrow{\oplus 6} 11 \xrightarrow{+6} 17,最终得到 c=17c=17,输出 YES

  • 第五组数据 2 7 8:无法通过操作从 22 得到 88,输出 NO

思路讲解

2025 ICPC Asia Manila Regional(2025 ICPC 马尼拉)——vp 中通过题目总结(把题目对取模的要求用注释写在末尾)

收到这场比赛的题目 E. Long Distance Examination(远程操作克隆机器人,两人在不同迷宫中,B 尽力复刻 A 的所有操作)的启发,我们决定重新把这道题目给再盘一盘。

其实说白了,这道题目也很简单,虽然说数字可能很大,但是,我们可以只关注在 (modb)\equiv\pmod b 的值,我们以这个为状态,进行记忆化 bfs,自然是非常少的(状态数)。

记忆化 bfs 最重要的就是确定状态**。**

当然,光有一个目前 mod b 的值是不够的,我们还需要再确定一个状态。

注意到,mod b 的值,是和这个 +b 相关的一个状态,这个提示我们,要采用一个和异或 b 相关的这个值,作为这个状态的组成部分。

注意到,异或 b 只能改变后 __lg(b)+1 位

因此,最后 __lg(b)+1 位,确定了异或 b 操作能够增长(或减小的值)。再加上 mod b 的值,就唯一确定了这个状态。因为起点确定了,增长的值也确定了,那就什么都确定了。(这个是因为异或具有不可重复操作性,操作偶数次等于不操作,操作奇数次等于操作一次)

1
2
3
4
5
6
7
struct ModB_Low_bit {
ll mod_b,low_bit,origin;
bool operator<(const ModB_Low_bit &o) const {
if (o.mod_b!=mod_b) return mod_b<o.mod_b;
return low_bit<o.low_bit;
}
};

AC代码

AC

https://qoj.ac/submission/1787588

AC

https://qoj.ac/submission/2095935

心路历程(WA,TLE,MLE……)

image

题目 H. Prime Topology

https://codeforces.com/gym/106262/problem/H

题目描述
定义集合 Un={1,2,3,,n}U_n = \{1, 2, 3, \dots, n\}
如果 UnU_n 的一个子集 SS 满足:对于 SS 中任意两个不同的元素 aabb,它们的绝对差 ab|a - b| 都是素数,则称该子集 SS素数间距的(prime-spaced)
给定正整数 nnkk,求在 UnU_n 中,大小为 kk 的素数间距子集的数量。
由于答案可能很大,请输出其对 104206969 取模后的结果。
本题包含多组独立测试数据。

输入格式
第一行包含一个整数 TT1T2×1051 \le T \le 2 \times 10^5),表示测试数据的组数。
接下来 TT 行,每行包含两个由空格分隔的整数 nnkk1kn1071 \le k \le n \le 10^7)。

输出格式
对于每组测试数据,输出一行,表示大小为 kk 的素数间距子集的数量对 104206969 取模的值。

样例输入

1
2
3
4
3
5 2
6 3
10000000 10000000

样例输出

1
2
3
5
2
0

样例解释
对于第一组样例 n=5,k=2n=5, k=2
U5={1,2,3,4,5}U_5 = \{1, 2, 3, 4, 5\},要求找出大小为 2 且元素差值的绝对值为素数的子集。
差值为 2(素数)的子集有:{1,3},{2,4},{3,5}\{1, 3\}, \{2, 4\}, \{3, 5\}
差值为 3(素数)的子集有:{1,4},{2,5}\{1, 4\}, \{2, 5\}
总共有 5 个满足条件的子集,故输出 5。

对于第二组样例 n=6,k=3n=6, k=3
U6={1,2,3,4,5,6}U_6 = \{1, 2, 3, 4, 5, 6\},要求找出大小为 3 且任意两个元素差值的绝对值均为素数的子集。
满足条件的子集仅有以下 2 个:

  1. {1,3,6}\{1, 3, 6\}:任意两元素差值分别为 13=2|1-3|=236=3|3-6|=316=5|1-6|=5,均为素数。

  2. {1,4,6}\{1, 4, 6\}:任意两元素差值分别为 14=3|1-4|=346=2|4-6|=216=5|1-6|=5,均为素数。
    总共有 2 个满足条件的子集,故输出 2。

对于第三组样例 n=10000000,k=10000000n=10000000, k=10000000
要求选出大小等于全集的子集,即只能选择集合本身。显然该集合中包含了差值为 1 的元素对(如 1 和 2,且 1 不是素数),因此不存在满足条件的子集,故输出 0。

首先要注意到,除了 2 以外所有的素数都是奇数,奇数+奇数就是偶数一定是可以被除的。所以说只能是 2+另一素数+2。

注意,这道题目的这个询问量特别高,因此要把东西都处理出来。

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
if (K==1) {
cout<<N<<"\n";
return;
}
ll ans=0;
// 除了 2 以外所有的素数都是奇数,奇数+奇数就是偶数一定是可以被除的
if (K==2) {
ans=N*cnt_prime[N]-pre_sum[N];
ans%=mod;
if (ans<0) {
ans+=mod;
}
cout<<ans<<"\n";
return;
}
if (K==3) {
ans=N*cnt_prime_add2[N-2]*2-pre_sum_add2[N-2];
ans%=mod;
if (ans<0) {
ans+=mod;
}
cout<<ans<<"\n";
return;
}
if (K==4) {
// 只有一个数,就是 3。
for (auto p:p_add4_is_p) {
ll len=p+2+2;
if (len>=N) {
break;
}
// if (minp[p+2+2]==p+2+2 && minp[p+2]==p+2) {
ans+=(N-len);
ans%=mod;
// }
}
cout<<ans<<"\n";
return;
}
if (K>=5) {
cout<<0<<"\n";
return;
}

AC
https://codeforces.com/gym/106262/submission/365350177

题目 E. Long Distance Examination(远程操作克隆机器人,两人在不同迷宫中,B 尽力复刻 A 的所有操作)

https://codeforces.com/gym/106262/problem/E

题目描述
Hero A 在网格 A 中,他正在远程控制位于网格 B 中的克隆人 Clone B 走迷宫
两个网格的大小均为 r×cr \times c。网格中包含空地(.)、障碍物(X)、起点(S)和终点(D)。起点 S 在两个网格中各出现一次,分别表示 Hero A 和 Clone B 的初始位置;终点 D 只在网格 B 中出现一次,表示 Clone B 需要到达的目的地。

Hero A 可以向上下左右四个方向移动,每次一步。他每尝试向某个方向移动一步,Clone B 也会尝试向相同的方向移动一步。移动规则如下

  1. 如果 Hero A 的移动方向被障碍物或网格边界阻挡,那么 Hero A 无法移动,此时 Hero A 和 Clone B 都不会移动

  2. 如果 Hero A 可以移动,但 Clone B 的移动方向被障碍物或边界阻挡,则 Hero A 会正常移动一步,而 Clone B 会停留在原地

  3. 如果两者前方均无阻挡,则两人都正常向该方向移动一步。

求使得 Clone B 到达终点 D,Hero A 最少需要移动的步数。如果无法到达,输出 -1

输入格式
第一行包含一个整数 TT1T101 \le T \le 10),表示测试数据的组数。
对于每组测试数据:
第一行包含两个由空格分隔的正整数 rrcc1r,c100,2r×c10001 \le r, c \le 100, 2 \le r \times c \le 1000)。
接下来 rr 行,每行包含一个长度为 cc 的字符串,表示网格 A 的状态。
再接下来 rr 行,每行包含一个长度为 cc 的字符串,表示网格 B 的状态。
字符仅包含 .XSD

输出格式
对于每组测试数据,输出一行,包含一个整数,表示最少需要的步数。如果不可达,则输出 -1

样例输入

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
2
5 5
S....
.....
.....
.....
.....
....S
.....
.....
.....
....D
7 5
XXXXX
XXXXX
XS..X
X.X.X
X...X
XXXXX
XXXXX
XXXXX
XS..X
XXX.X
X...X
XXX.X
XD..X
XXXXX

样例输出

1
2
4
14

样例解释
对于第一组样例:
网格 A 的起点在左上角,网格 B 的起点在右上角,终点在右下角。尽管 Hero A 和 Clone B 的起点不同,由于两个网格中间都没有障碍物,Hero A 只需要一直向下走 4 步,Clone B 也会无阻挡地同时向下走 4 步到达终点。最少步数为 4。

对于第二组样例:
Hero A 位于网格 A 的 (3, 2),而 Clone B 位于网格 B 的 (2, 2)。由于网格 B 中有较多障碍物阻挡了直接向下走向终点的路径,Hero A 可以利用“自己移动而 Clone B 被墙挡住留在原地”的机制来调整两者之间的相对位置。
最优解是 Hero A 在网格 A 中顺时针绕行:

  • Hero A 走一圈(右右下下左左上上,共 8 步)回到原点,此时 Clone B 会在跟随移动的过程中被障碍物卡住,最终停留在网格 B 的 (4, 2) 位置。

  • 随后 Hero A 继续走第二圈(右右下下左左,走 6 步时),Clone B 会顺势移动到 (6, 2) 的终点 D
    总共花费 8+6=148 + 6 = 14 步,使得 Clone B 到达终到达终点。

比较像这道题目 2025 CCPC 郑州的这道题目。

https://qoj.ac/contest/2661/problem/15307

2025 CCPC 郑州——G. Plus Xor( n 方复杂度,要想到记忆化 bfs 搜索)(记忆化 bfs 最重要的就是确定状态)(异或 b 只能改变 __lg(b)+1 位)(采用塞入的时候确定答案的,应该采用一 check/is_find_ans 函数,确保初始塞入情况和中途塞入情况采用同样的判断逻辑)

这道题目比这个 G 简单,比较容易发现:

1
2
3
4
5
6
7
8
9
struct XY_AB{
ll xa,ya,xb,yb;
bool operator<(const XY_AB &o) const {
if (xa!=o.xa) return xa<o.xa;
if (ya!=o.ya) return ya<o.ya;
if (xb!=o.xb) return xb<o.xb;
return yb<o.yb;
}
};

一个完整状态由 A 的位置和这个 B 的位置确定,我们只需要对这一状态进行记忆化 bfs 即可。

AC
https://codeforces.com/gym/106262/submission/365338227

题目3

题目4

题目5

一、减少约束条件 / 从特殊情况入手(对于明显堆砌约束条件的题目较为有效)

Codeforces Round 1083 (Div. 2)——CF-2205-F. Simons and Reconstructing His Roads(遇到一道题目没有思路,可以先降低约束试一试)(±±,需要想到差分)(对割的理解以及使用)(格林公式的应用)

像这道题目,对于重建的这个约束太多。

Consider the case without any “accidents”, i.e., when there are no additional restrictions on the reconstructed streets.

不过,悲观地而言,只应用这一技巧想把这道题目做出来没什么用啊。

二、整体化为局部(格林公式,最优子结构,贪心)

Codeforces Round 1083 (Div. 2)——CF-2205-F. Simons and Reconstructing His Roads(遇到一道题目没有思路,可以先降低约束试一试)(±±,需要想到差分)(对割的理解以及使用)(格林公式的应用)

题目大意

题目大意

给定一个 n×mn \times m 的网格图,包含交汇点 (1,1)(1,1)(n,m)(n,m)。网格中的相邻交汇点之间存在道路:

  • (i,j)(i,j)(i+1,j)(i+1,j) 之间为垂直道路,其权值为 wi,jw_{i,j}

  • (i,j)(i,j)(i,j+1)(i,j+1) 之间为水平道路,其权值为 vi,jv_{i,j}

由于一些事故,部分道路无法被重建(由输入状态 00 表示),其余道路可选择是否重建(由输入状态 11 表示)。

对于网格中的任意一个交汇点,如果与其相连且最终被重建的道路数量为偶数,则称该交汇点是“优雅的”。
如果所有的交汇点都是“优雅的”,则称当前的整个道路重建方案是“完美的”。

美丽值计算方式

对于一个“完美的”重建方案,其“美丽值”的计算方式如下:

  1. 初始美丽值为 00

  2. 对于每一行 ii (1in11 \le i \le n-1),找出所有在这一行向下延伸(即连接 (i,j)(i,j)(i+1,j)(i+1,j))且被重建的垂直道路。设它们所在的列号从小到大依次为 c1<c2<c3<c_1 < c_2 < c_3 < \dots,则将 wi,c1wi,c2+wi,c3wi,c4+w_{i,c_1} - w_{i,c_2} + w_{i,c_3} - w_{i,c_4} + \dots 累加到美丽值中。

  3. 对于每一列 jj (1jm11 \le j \le m-1),找出所有在这一列向右延伸(即连接 (i,j)(i,j)(i,j+1)(i,j+1))且被重建的水平道路。设它们所在的行号从小到大依次为 r1<r2<r3<r_1 < r_2 < r_3 < \dots,则将 vr1,jvr2,j+vr3,jvr4,j+v_{r_1,j} - v_{r_2,j} + v_{r_3,j} - v_{r_4,j} + \dots 累加到美丽值中。
    (简单来说,就是分别对“每行向下的重建道路”和“每列向右的重建道路”按坐标顺序交替加减其权值)

目标:在所有“完美的”重建方案中,求出最大的“美丽值”。

image

输入格式

  • 第一行包含测试用例数 tt (1t51041 \le t \le 5 \cdot 10^4)。

  • 每个测试用例的第一行包含 nnmm (2n,m2105,nm41052 \le n, m \le 2 \cdot 10^5, \sum n \cdot m \le 4 \cdot 10^5)。

  • 接下来 n1n-1 行,每行 mm 个整数,表示垂直道路的权值 wi,jw_{i,j}

  • 接下来 nn 行,每行 m1m-1 个整数,表示水平道路的权值 vi,jv_{i,j}

  • 接下来 n1n-1 行,每行一个长度为 mm 的 01 字符串,表示各条垂直道路是否可以被重建。

  • 接下来 nn 行,每行一个长度为 m1m-1 的 01 字符串,表示各条水平道路是否可以被重建。

输出格式

对于每个测试用例,输出一个整数,表示在所有完美重建方案中能获得的最大美丽值。

样例数据

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
4
3 4
2 3 -2 3
4 9 4 -4
3 4 -2
-9 -5 1
6 -1 -3
1111
1111
111
111
111
2 4
4 23 1 35
6 12 -17
-14 1 -40
0100
000
101
3 3
1 0 1
0 1 0
1 0
0 1
0 0
110
111
10
11
11
3 4
13 7 6 -12
3 -5 12 -6
-3 10 -15
-5 8 -11
10 0 -5
1111
0110
110
101
010

样例解释

以第一个测试用例为例(n=3,m=4n=3, m=4,且所有道路均允许重建),在使得所有交汇点相连重建道路数均为偶数的前提下,取得最大美丽值的方案如下:

垂直道路(向下的边)的选择

  • 第 1 行向下重建位于列 1、列 3 的道路,权值分别为 2,22, -2,贡献值为:2(2)2 - (-2)

  • 第 2 行向下重建位于列 2、列 4 的道路,权值分别为 9,49, -4,贡献值为:9(4)9 - (-4)

水平道路(向右的边)的选择

  • 第 1 列向右重建位于行 1、行 2 的道路,权值分别为 3,93, -9,贡献值为:3(9)3 - (-9)

  • 第 2 列向右重建位于行 1、行 3 的道路,权值分别为 4,14, -1,贡献值为:4(1)4 - (-1)

  • 第 3 列向右重建位于行 2、行 3 的道路,权值分别为 1,31, -3,贡献值为:1(3)1 - (-3)

该方案不仅满足所有交汇点度数皆为偶数,且其总美丽值为:
(2(2))+(9(4))+(3(9))+(4(1))+(1(3))(2 - (-2)) + (9 - (-4)) + (3 - (-9)) + (4 - (-1)) + (1 - (-3))
=4+13+12+5+4=38= 4 + 13 + 12 + 5 + 4 = 38

在第二个测试用例中,受限于无法重建的道路限制,唯一的完美重建方案是“不重建任何道路”,因此最大美丽值为 00

思路讲解

像这道题目,对于重建的这个约束太多。

Consider the case without any “accidents”, i.e., when there are no additional restrictions on the reconstructed streets.

我们可以先把所有对于重建边操作的限制,就是有一些边不能进行重建操作,给删除,我们会做了吗?(注意这里不能够把这个偶数条边的这个结果也给删了)

其实也没有那么简单,你首先要注意到,对于一维问题,成对的±,相当于一系列差分的和。那么,还需要特意去选吗?直接选全部为正的差分值不就好了?(连续选了两个或更多差分值,有重叠也没关系,可以使用我们下图的逆运算)

image

但是这个只能解决成对的 ± 问题呀,要是 ±+,以 + 结尾的不成对串如何解决呢?

来,我们仔细看看。只需要在末尾加一个 0,然后采用同样的贪心即可。

image

好,下面我们要正式解决这个问题了。

问题来到了 2D,我们发现有一个这个约束,就是,点的偶数边重建约束,这个还是有点烦的,怎么样去解决这个问题?

不难想到,如果一个点的边是否重建受到约束,我们能不能找到一个东西,其无论怎么样取,都符合约束呢?这样无论是贪心还是 dp,都会好解决的多。

Codeforces Round 1026 (Div. 2)-CF-1026-E. Melody

Codeforces Round 1081 (Div. 2)-CF-1081-E. Swap to Rearrange(按值进行图论建模)(欧拉回路)

通过这些题目,我们知道,如果说所有的点的度数都是偶数,组成的一定是一个欧拉回路(在无向联通图中)。

那么在这道题目中,题目所给我们的图,实际上是一个对偶图(就是边不相交的平面图,显然,网格图是对偶图),欧拉回路在对偶图中,实际上是一个割(这个是不难得出的,说白了,你在平面上一笔画出一条回路,当然能把平面划分为两部分,特别还要求你的这个路径是不会自相交的,因为所有边都互不相交)。注意,可以确定的是,这些欧拉回路

那既然是一个割,把一个面分割成了两部分,我们就想到了黑白染色

这个时候求解为什么能想到小的单位面元?从更高的观点来看,其实这个是离散型二维格林公式

image

具体而言,如下图所示:

image

现在问题在于如何处理这个有些边不能进行重建操作?

image

那么上图已经讲的很清楚了,不能重建的边,就像是胶水,直接把这两块给粘起来,这条边就不会再操作了。唯一一个特殊点就是最边上的边就是和外部联通了,这里我们需要设置一个外部节点 out_node,把他和 out 连接在一起即可。

AC代码

AC
https://codeforces.com/contest/2205/submission/365321534

心路历程(WA,TLE,MLE……)

哎,非常经典的错误啊

在并查集中,直接改动节点的值是非常幼稚的,因为你不知道他是不是根节点,当然你可以 find 后改根节点。

image

AC

https://codeforces.com/contest/2205/submission/365204709

AI 代码确实是没什么问题。