0%

题目大意

题目描述
给定一个长度为 nn 的正整数数组,求有多少个非空连续子数组满足以下条件:子数组内所有元素的和,能够被该子数组中所有元素包含的数字字符的最大值整除。

(注:数字字符指组成数字的 090 \sim 9。例如,数组 [2025, 11, 15] 中包含的数字字符有 0,1,2,50, 1, 2, 5,其最大值为 55。)

输入格式
第一行包含一个整数 TT1T1041 \le T \le 10^4),表示测试用例的数量。
对于每个测试用例:
第一行包含一个整数 nn1n1051 \le n \le 10^5),表示数组长度。
第二行包含 nn 个正整数 x1,x2,,xnx_1, x_2, \dots, x_n1xi1091 \le x_i \le 10^9),表示数组元素。
保证所有测试用例中 nn 的总和不超过 10510^5

输出格式
对于每个测试用例,输出一行一个整数,表示满足条件的非空子数组数量。

样例输入

1
2
3
4
5
2
3
213 12 21
7
314 880 246 170 493 474 129

样例输出

1
2
4
7

样例解释
以第一个测试用例 [213, 12, 21] 为例,考察其所有非空子数组:

  • [213]:包含数字 1,2,31, 2, 3,最大数字为 33。子数组元素和为 213213213mod3=0213 \bmod 3 = 0满足条件

  • [12]:包含数字 1,21, 2,最大数字为 22。子数组元素和为 121212mod2=012 \bmod 2 = 0满足条件

  • [21]:包含数字 1,21, 2,最大数字为 22。子数组元素和为 212121mod2021 \bmod 2 \neq 0,不满足条件。

  • [213, 12]:包含数字 1,2,31, 2, 3,最大数字为 33。子数组元素和为 213+12=225213 + 12 = 225225mod3=0225 \bmod 3 = 0满足条件

  • [12, 21]:包含数字 1,21, 2,最大数字为 22。子数组元素和为 12+21=3312 + 21 = 3333mod2033 \bmod 2 \neq 0,不满足条件。

  • [213, 12, 21]:包含数字 1,2,31, 2, 3,最大数字为 33。子数组元素和为 213+12+21=246213 + 12 + 21 = 246246mod3=0246 \bmod 3 = 0满足条件

满足条件的子数组共有 4 个。

思路讲解

≤d 比=d 好计数得多,那为什么不使用 f(≤d)-f(≤d-1) 得到 f(=d) 呢?

不过,要注意到,就是光一个 d 是不够描述这个 f 函数的。

定义 $ f(≤d,big_d)$ 指的是最大 digit 是 d≤d 而且可以被 bigdbig_d 整除的这个子段数量。

因此,不难发现 $ f(=d,big_d)=f(≤d,big_d)-f(≤d-1,big_d)$。

使用这一容斥方法解决该问题,是因为我们发现在编程中,我们发现,很难对 最大 digit=d 进行计数(你要是不信的话可以自此试试)。

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
for (int big_d=1;big_d<=9;++big_d) {
vector<ll> F(10+2);
for (int d=big_d-1;d<=big_d;++d) {
vector<ll> R(big_d);
for (int i=1;i<=N;++i) {
if (mx_d[i]>d) {
// if (find_mx) {
// ans+=R[0];
// }
R.assign(big_d,0);
continue;
}
// cal(A[i]);
ll rem=A[i]%big_d;
rotate(R.rbegin(),R.rbegin()+rem,R.rend());
R[rem]++;
F[d]+=R[0];

// if (find_mx) {
// ans+=R[0];
// }
}
}
ans+=F[big_d]-F[big_d-1];
}

AC代码

AC
https://codeforces.com/gym/106380/submission/366441214

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

题目大意

题目描述

给定一个正整数 nn 以及两个长度为 nn 的排列 rrcc
请构造一个 n×nn \times n 的矩阵,满足以下所有条件:

  1. 矩阵中的所有元素均为 [0,n][0, n] 范围内的整数。

  2. 矩阵第 ii 行元素的 MEX\text{MEX} 值为 rir_i

  3. 矩阵第 ii 列元素的 MEX\text{MEX} 值为 cic_i

注:数组的 MEX\text{MEX} 值是指数组中未出现的最小非负整数。题目保证必然存在符合上述条件的矩阵。

输入格式

第一行包含一个整数 TT1T1031 \le T \le 10^3),表示测试用例的数量。
对于每个测试用例:
第一行包含一个正整数 nn1n2×1031 \le n \le 2 \times 10^3)。
第二行包含一个长度为 nn 的排列 r1,r2,,rnr_1, r_2, \dots, r_n
第三行包含一个长度为 nn 的排列 c1,c2,,cnc_1, c_2, \dots, c_n
保证所有测试用例中 nn 的总和不超过 2×1032 \times 10^3

输出格式

对于每个测试用例,输出 nn 行,每行包含 nn 个整数,表示满足所有条件的矩阵。如果有多个符合条件的矩阵,输出其中任意一个即可。

样例数据

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

输出:
0 0 4 1
2 3 4 0
1 2 0 1
0 1 2 3
0 0 0 0 1
0 0 0 2 0
2 3 3 1 0
2 1 0 4 2
0 2 1 3 4

样例解释

以第一个测试用例为例,n=4n = 4r=[2,1,3,4]r = [2, 1, 3, 4]c=[3,4,1,2]c = [3, 4, 1, 2]
对于输出的矩阵:

  • 11 行元素为 [0,0,4,1][0, 0, 4, 1],其中包含 0,1,40, 1, 4,未出现的最小非负整数为 22,等于 r1r_1

  • 22 行元素为 [2,3,4,0][2, 3, 4, 0],其中包含 0,2,3,40, 2, 3, 4,未出现的最小非负整数为 11,等于 r2r_2

  • 33 行元素为 [1,2,0,1][1, 2, 0, 1],其中包含 0,1,20, 1, 2,未出现的最小非负整数为 33,等于 r3r_3

  • 44 行元素为 [0,1,2,3][0, 1, 2, 3],其中包含 0,1,2,30, 1, 2, 3,未出现的最小非负整数为 44,等于 r4r_4

同理观察列方向上的 MEX\text{MEX} 值:

  • 11 列元素为 [0,2,1,0][0, 2, 1, 0],包含 0,1,20, 1, 2,其 MEX\text{MEX} 值为 33,等于 c1c_1

  • 22 列元素为 [0,3,2,1][0, 3, 2, 1],包含 0,1,2,30, 1, 2, 3,其 MEX\text{MEX} 值为 44,等于 c2c_2

  • 33 列元素为 [4,4,0,2][4, 4, 0, 2],包含 0,2,40, 2, 4,其 MEX\text{MEX} 值为 11,等于 c3c_3

  • 44 列元素为 [1,0,1,3][1, 0, 1, 3],包含 0,1,30, 1, 3,其 MEX\text{MEX} 值为 22,等于 c4c_4

所有行和列的 MEX\text{MEX} 值均完全符合输入的排列要求,该矩阵合法。

思路讲解

不难注意到这样一个构造方法。

image

然后,其实我们自己也想到了,一个构造方法,可以通过行列交换,得到新的,任何符合要求的这个 mex 矩阵。

通过行交换,可以使得列的条件依然得到满足。通过列交换,可以使得行的条件依然得到满足

因此,现应用行交换,再应用列交换,就可以把一个这个构造方法变成任何东西。

1
2
3
4
5
6
7
8
for (int i_R=1;i_R<=N;++i_R) {
ll i=R[i_R];
for (int j_C=1;j_C<=N;++j_C) {
ll j=C[j_C];
cout<<maze[i][j]<<" ";
}
cout<<"\n";
}

AC代码

AC
https://codeforces.com/gym/106380/submission/366322358

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

The 21st Hunan Provincial Collegiate Programming Contest

可以优先做国内的这个省赛

2025 National Invitational of CCPC (Zhengzhou), 2025 CCPC Henan Provincial Collegiate Programming Contest

郑州的这个 CCPC 邀请赛。

我感觉国内的这个感觉和国外不大一样,可以优先 vp 国内的省赛(国内区域赛可以留到比赛前 vp,没必要最近 vp)。

The 2025 Jiangsu Collegiate Programming Contest, The 2025 Guangdong Provincial Collegiate Programming Contest

image

The 15th Shandong CCPC Provincial Collegiate Programming Contest

image

The 18th Jilin Provincial Collegiate Programming Contest

image

2025 ICPC Nanchang Invitational and Jiangxi Provincial Collegiate Programming Contest

image

The 13th Shaanxi Provincial Collegiate Programming Contest

image

ICPC Asia Dhaka Regional Onsite 2025 — Replay Contest

cf 上做的人很多

image

题目大意

题目描述
给定一棵包含 nn 个节点的无根树。

Cyndaquil 起初位于一个非叶子节点 vv。在每一个回合中,他可以选择停留在当前节点,或者移动到相邻的一个节点。他的目标是到达树的任意一个叶子节点(度数为 11 的节点)。

Snorlax 试图阻止他到达叶子节点。Snorlax 可以选择在一条边上睡觉,此时 Cyndaquil 将无法通过这条边。同一时刻最多只有一条边会被阻塞(即只有最新选择的边会被阻塞)。

Snorlax 移动有冷却时间。初始时冷却时间为 00。当冷却时间 0\le 0 时,Snorlax 可以选择一条新的边进行阻塞(他也可以选择暂不行动)。一旦他移动并选择了一条新边,冷却时间就会重置为 kk

在 Cyndaquil 的每个回合之后(即使他选择停留),Snorlax 的冷却时间都会减少 11

两人轮流行动,Snorlax 先手,且初始时没有任何边被阻塞。假设双方都采取最优策略,判断 Cyndaquil 是否一定能在有限的回合内到达某个叶子节点。

输入格式
第一行包含一个整数 tt (1t1041 \le t \le 10^4),表示测试用例的数量。

每个测试用例的第一行包含三个整数 nnkkvv (3n51053 \le n \le 5 \cdot 10^51k,vn1 \le k, v \le n),分别表示树的节点数、Snorlax 的冷却时间以及 Cyndaquil 的初始起点。

接下来 n1n-1 行,每行包含两个整数 aabb (1a,bn1 \le a, b \le naba \neq b),表示树上连接节点 aabb 的一条边。

保证给定的图是一棵树,且起点 vv 不是叶子节点。所有测试用例的 nn 之和不超过 51055 \cdot 10^5

输出格式
对于每个测试用例,输出一行 “YES” 或 “NO”(大小写不敏感),表示 Cyndaquil 是否一定能在有限回合内到达叶子节点。

样例输入

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
6
6 2 1
1 2
2 3
2 4
1 5
5 6
7 1 4
1 2
2 3
3 4
4 5
5 6
6 7
3 1 3
1 3
2 3
4 1 4
1 3
3 4
4 2
9 3 5
4 5
5 6
4 7
9 8
8 7
1 2
2 3
3 4
9 4 5
4 5
5 6
4 7
9 8
8 7
1 2
2 3
3 4

样例输出

1
2
3
4
5
6
YES
NO
YES
NO
NO
YES

样例解释
在第一个测试用例中:Cyndaquil 从节点 11 出发。如果 Snorlax 选择阻塞节点 11 到节点 22 的边,那么 Cyndaquil 可以在两个回合后走到叶子节点 66。否则,Cyndaquil 可以直接移动到节点 22,此时 Snorlax 无法同时阻止他前往叶子节点 3344,Cyndaquil 必然能到达其中一个。

在第二个测试用例中:由于冷却时间 k=1k=1 极短,Snorlax 可以频繁移动,可以证明 Snorlax 能够无限期地阻止 Cyndaquil 到达树两端的叶子节点 1177

image

不难发现样例 2,移动者会被困在 3,4 之间,因为阻塞者冷却时间太快了,只有 1。

image

样例 5 到达不了叶子节点

暴力程序书写指导

暴力程序 bfs 的书写**,最重要的还是和做题的一样的,用什么代表一个状态。**

为什么要书写暴力 bfs 程序?因为以我的这个经验,这种图论题目,你想一遍写对,基本不可能,以类似题目 F 为例:

2025-沈阳站-区域赛-F. The Bond Beyond Time(友谊天长地久)(如何使用 bfs 找一个无弦环)(这种题目,我感觉啊,想要做出来的话,要么就是你的思路得比较好,要么就是还是得写个对拍)

这道题目有一个地方还是很难想到的,需要写一个对拍。

在写一个暴力程序之前(当然,特别暴力的除外啊,特别暴力的就不用想了,但是不是所有的题目都可以非常轻松的找到一个特别暴力的写法,特别是这种博弈题目),一定要想清楚这个状态转移图像

我们不难得到这样的图像:

image

然后,我们来想如何具体实现,这种样子,我们非常容易想到这个记忆化 dfs。但是有环的话,不能够使用记忆化 dfs,毕竟记忆化 dfs 就是 dp,只能够在 DAG 上使用

于是我们想到记忆化 bfs。但是一次正向的记忆化 bfs 很难实现类似的这种可以计算前驱后驱的这个复杂运算。

但是一次不行,就跑两次呗。我们可以跑一次正向 bfs,记住这个出去的红色节点数量(即红色出度)和出去的这个蓝色节点数量(即蓝色出度)。(你也可以理解这次 bfs 就是在把这张反图建出来,毕竟不把图建出来,很难进行这个反向 bfs)然后再跑一次这个反向 bfs,从所有合法点一路往上推,通过减去红色计数器和蓝色计数器,实现类似于或的效果,把红色计数器和蓝色计数器并起来,实现红蓝 and 的效果。

当然我们也不知道对不对,试一试吧。

试过了,上面👆这种做法很难写对,也不是错吧,很难写对。我们不妨啊,一轮,拆成两个操作来看,这样可以避免红蓝之间转移的尴尬问题。

image

一定要把这个状态转移图设计为红蓝互不相交的情况,至少要把逃跑者选择和阻塞者选择分开

好的暴力果然是非常优美啊,一次写对。

采用了朴素的,不动点式的更新方法:

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
bool changed=true;
while (changed) {
changed=false;
for (const auto &[u,vec]:complex_g) {
if (win[u]) continue;
if (u.turn) {
bool all_win=true;
for (auto son:vec) {
if (!win[son]) {
all_win=false;
break;
}
}
win[u]=all_win;
if (all_win) {
changed=true;
}
}else {
for (auto son:vec) {
if (win[son]) {
win[u]=true;
changed=true;
break;
}
}
}
}
}

思路讲解

S 只要符合这个要求,就是 Yes,否则就是 No。

image

其实像上面👆这么想,有一个非常阴的地方,就是,阻塞者是动态的,且可以不操作的,阻塞者可能不急于操作,而是看你怎么操作以后,他再出手,逼你从优势位置移动出来。这么讲很抽象是吧?我们直接拿对拍出来的样例来说。

1
2
3
4
5
6
7
8
9
1
7 2 1
1 2
1 3
2 4
1 5
5 6
3 7

这个样例应该输出 no,原因和上面说的一样。阻塞者可能不急于操作,而是看你怎么操作以后,他再出手,逼你从优势位置移动出来

image

所以说要怎么解决这个问题呢?还是挺难的。

像这种博弈题目,一定要想到的就是两者的最优策略是什么?一定要想两者的最优策略是什么。

Snorlax 试图阻止 Cyndaquil 到达叶子节点,他的最优策略是在 Cyndaquil 即将到达叶子节点(或必胜节点)前的最后一步进行封锁。我们其实已经通过对拍呀,通过什么方式找到了这个比较特殊的这个例子。但是我们没有总结出来,就是阻塞者他的这个策略是什么,就这种博弈题目一定要去想他们的最优策略是什么

因此,其实我们就是看这个拉扯距离

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
auto dfs=[&](auto && go,ll u,ll fa) -> void {
if (SZ(g[u])==1) {
return;
}
vector<ll> rec;
ll lans=INF;
for (auto to:g[u]) {
if (to==fa) {
continue;
}
go(go,to,u);
rec.push_back(dp[to]);
lans=min(dp[to]+1,lans);
}
sort(all(rec));
if (SZ(rec)>=2) {
// rec[0]+rec[1]+2 是拉扯距离总长度
// -1 是因为这个在最后一刻他卡你一下,你需要跑的距离就是总拉扯距离 -1
if (rec[0]+rec[1]+2-1<=K) {
lans=0;
}
}
dp[u]=lans;
};
dfs(dfs,S,-1);
if (dp[S]==0) {
cout<<"YES\n";
return;
}
cout<<"NO\n";

AC代码

AC
https://codeforces.com/contest/2207/submission/366188285

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

题目大意

题目描述

一共有 mm 个玩偶,初始危险值 d1,d2,,dmd_1, d_2, \dots, d_m 均为 0。

整个过程持续 \ell 秒。在每一秒内,会有一个(且仅有一个)玩偶的危险值增加 1。你可以时刻观察到所有玩偶当前的危险值。

你有 nn 次使用手电筒的机会,分别在固定的时间点 a1,a2,,ana_1, a_2, \dots, a_n1a1<a2<<an1 \le a_1 < a_2 < \dots < a_n \le \ell)秒后发生。
每次使用手电筒时,你可以选择恰好一个玩偶,将其危险值重置为 0。每次的选择是互相独立的。

最终的“总危险值”定义为 \ell 秒结束时,所有玩偶危险值的最大值,即 max1jmdj\max_{1 \le j \le m} d_j
你需要求出一个最小的整数 xx,使得无论每一秒是哪个玩偶的危险值增加,你都能通过合理地使用手电筒,保证最终的总危险值不超过 xx

输入格式

第一行包含一个整数 tt1t1041 \le t \le 10^4),表示测试用例的数量。

每个测试用例的第一行包含三个整数 n,m,n, m, \ell1n,m,21051 \le n, m, \ell \le 2 \cdot 10^5nn \le \ell1m21051 \le m \cdot \ell \le 2 \cdot 10^5),分别代表手电筒使用次数、玩偶数量以及总时长。

第二行包含 nn 个整数 a1,a2,,ana_1, a_2, \dots, a_n1a1<a2<<an1 \le a_1 < a_2 < \dots < a_n \le \ell),代表可以使用手电筒的时间点。

保证所有测试用例中 mm \cdot \ell 的总和不超过 21052 \cdot 10^5

输出格式

对于每个测试用例,输出一个整数,即保证最终总危险值不超过的最小值 xx

样例数据

输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7
1 2 10
10
5 1 32
1 4 9 16 25
2 3 40
13 37
2 2 7
6 7
8 5 60
3 17 20 28 36 44 45 50
6 7 1987
6 7 66 77 666 777
1 1 1
1

输出

1
2
3
4
5
6
7
5
7
19
1
19
1477
0

样例解释

在第一个测试用例中,有 22 个玩偶,总时长为 1010 秒,在第 1010 秒后可使用一次手电筒。可以证明 x=5x=5 总是可行的:1010 秒后,必定有一个玩偶的危险值至少为 55,另一个至多为 55。我们对着危险值较大的那个使用手电筒将其清零,那么最终的最大危险值至多为 55。可以证明 55xx 的最小可能值。

在第二个测试用例中,只有 11 个玩偶,总时长为 3232 秒。由于只有 11 个玩偶,它的危险值每秒必定增加 11。在最后一次使用手电筒(第 2525 秒)时,我们将它的危险值清零。在这之后距离结束还有 77 秒,因此最终危险值必定为 77

在第三个测试用例中,可以证明最小可能的值 xx1919

思路讲解

就是这个 B,哎,感觉基本上是想到了,但是没关注到一个关键的这个数据范围限制

一定要关注数据范围限制

image

你看到这个,基本就知道简单的贪心和这个二分答案是解决不了的。

其实这道题目,这个思路还是不难的,就是,我们想让我们的每一次操作都在最终的答案中贡献最大,是不是?

然后我们发现,如果说后面还有 N 个手电筒,我们如果给 N 个球加,我们其实对这个最终答案的贡献是 0。

image

那怎么办?我们可以给 N+1 个球加。

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ll cnt=N;
while (SZ(st)>cnt+1) {
pop();
}
for (int i=1;i<=L;++i) {
add();
if (incident[i]) {
to_zero();
--cnt;
}
while (SZ(st)>cnt+1) {
pop();
}
}
ll ans=*st.rbegin();

AC代码

AC

https://codeforces.com/contest/2207/submission/365942294

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