0%

题目大意

题目大意

给定一个 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 代码确实是没什么问题。

题目大意

题目描述

给定一个长度为 nn 的目标数组 TT

现有一个与 TT 等长的初始数组 SS,对 SS 进行恰好一次如下操作:
选择一个整数 kk,并将数组 SS 划分为 kk 个连续且不重叠的子段。假设这 kk 个子段的下标区间依次为 [l1,r1],[l2,r2],,[lk,rk][l_1, r_1], [l_2, r_2], \dots, [l_k, r_k],满足 l1=1l_1=1rk=nr_k=n,且对于所有的 1ik11 \le i \le k-1,都有 ri+1=li+1r_i + 1 = l_{i+1}
然后,对这 kk 个子段分别独立地进行翻转操作。

即,选择的区间形如:

image

请求出有多少种不同的初始数组 SS,可以通过上述操作变为目标数组 TT。由于答案可能很大,请输出其对 998244353998244353 取模后的结果。

输入格式

第一行包含一个整数 tt1t80001 \le t \le 8000),表示测试用例的数量。
每组测试用例的第一行包含一个整数 nn1n80001 \le n \le 8000),表示数组的长度。
第二行包含 nn 个整数 T1,T2,,TnT_1, T_2, \dots, T_n1Ti80001 \le T_i \le 8000),表示目标数组 TT 的元素。
保证所有测试用例中 nn 的总和不超过 80008000

输出格式

对于每组测试用例,输出一个整数,表示满足条件的数组 SS 的数量对 998244353998244353 取模后的结果。

样例输入

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

样例输出

1
2
3
4
5
4
7
22
383
1

样例解释

在第一组测试用例中,T=[1,1,2,1]T = [1, 1, 2, 1],以下 44 种数组 SS 可以被转换为 TT

  • 对于 S=[2,1,1,1]S = [2, 1, 1, 1],可以选择区间 [1,3][1, 3][4,4][4, 4] 进行翻转。翻转后数组变为 [1,1,2,1][1, 1, 2, 1],等于 TT

  • 对于 S=[1,2,1,1]S = [1, 2, 1, 1],可以选择区间 [1,4][1, 4] 进行翻转。

  • 对于 S=[1,1,2,1]S = [1, 1, 2, 1],可以选择区间 [1,2][1, 2][3,3][3, 3][4,4][4, 4] 进行翻转。

  • 对于 S=[1,1,1,2]S = [1, 1, 1, 2],可以选择区间 [1,2][1, 2][3,4][3, 4] 进行翻转。

在第二组测试用例中,T=[1,2,3,1]T = [1, 2, 3, 1],以下 77 种数组 SS 可以被转换为 TT

  • 对于 S=[1,1,3,2]S = [1, 1, 3, 2],可以选择区间 [1,1][1, 1][2,4][2, 4] 进行翻转。

  • 对于 S=[1,2,1,3]S = [1, 2, 1, 3],可以选择区间 [1,1][1, 1][2,2][2, 2][3,4][3, 4] 进行翻转。

  • 对于 S=[1,2,3,1]S = [1, 2, 3, 1],可以选择区间 [1,1][1, 1][2,2][2, 2][3,3][3, 3][4,4][4, 4] 进行翻转。

  • 对于 S=[1,3,2,1]S = [1, 3, 2, 1],可以选择区间 [1,4][1, 4] 进行翻转。

  • 对于 S=[2,1,1,3]S = [2, 1, 1, 3],可以选择区间 [1,2][1, 2][3,4][3, 4] 进行翻转。

  • 对于 S=[2,1,3,1]S = [2, 1, 3, 1],可以选择区间 [1,2][1, 2][3,3][3, 3][4,4][4, 4] 进行翻转。

  • 对于 S=[3,2,1,1]S = [3, 2, 1, 1],可以选择区间 [1,3][1, 3][4,4][4, 4] 进行翻转。

思路讲解

分析 rev 操作的一个重要公式是

rev(XY)=rev(Y)rev(X)\text{rev}(XY) = \text{rev}(Y)\text{rev}(X)

可以继续拓展:

image

image

所以,我们要求转移时前缀相同,只采用这一后缀,即可得到独特的计数

具体来讲,我们对这一后缀的要求是(在前缀相同的情况下)这一后缀无论如何划分,都达不到整体的效果。

1
rev(S) != rev(任意对S的划分方法)

比如说 [1, 2, 3, 4] 任何其他划分方式都达不到 rev([1, 2, 3, 4]) 的效果。

image

image

image

image

不过上面,opus4.6 给出的解释实际上不是很令人满意,因为带有非常明显的知道答案,凑出证明的痕迹。我们采用一种更加好的方法?(可能没有那么严谨,但是实际上是严谨的)

image

P4391 [BalticOI 2009] Radio Transmission 无线传输

我们不难发现,可以这种所谓的查找目标 C=CC=C',其实就是查找周期,其实和查找周期的哈希实现一模一样(详见上面一道题目)。

image

相信看了我的这个解释,应该都能看出来这个东西。

其实,形如 rev(S)=rev(ABA)rev(S)=rev(ABA),其实是唯一一种形式,可以保证分段反转等于整体反转。

不过快速检查一个字符串是否有真前后缀相同,显然是使用 kmp(前缀数组,前缀数组就是这么定义的,能不好吗?) 还是比较好的,使用字符串哈希时间复杂度不是很优秀。

P3375 【模板】KMP(前缀函数)

好,现在问题就来到了,我们怎么样求 s[l;r]s[l;r] 是否有这个真前后缀匹配情况?

image

哈哈,其实解决这个问题的方法也很简单,那么就是跑 n 遍 kmp 就可以了,这道题目不是 O(n2)O(n^2) 的嘛。绷不住了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
vector<ll> kmp(ll N,const vector<ll> &A){	// 返回总前缀数组pi
vector<ll> pi(N+2);
for(int i=2;i<=N;++i){
ll len=pi[i-1];
// if(S[i]==S[len+1]){
// pi[i]=len+1;
// }
while(true){
if(A[i]==A[len+1]){
pi[i]=len+1;
break;
}
if(len==0) break;
len=pi[len];
}
}
return pi;
}

最后的这个 dp 代码:

1
2
3
4
5
6
7
8
9
10
11
for (int l=1;l<=N;++l) {
vector<ll> pi=kmp(N-l+1,vector<ll>(A.begin()+l-1,A.end()));
ll offset=l-1;
for (int r=l;r<=N;++r) {
if (pi[r-offset]>0) {
continue;
}
dp[r]+=dp[l-1];
dp[r]%=mod;
}
}

AC代码

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

这个代码跑的好快啊,竟然

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

要好好想清楚这个 dp 是从哪里转移过来的,是从 l-1 转移过来的

1
2
3
4
5
6
7
8
9
10
11
for (int l=1;l<=N;++l) {
vector<ll> pi=kmp(N-l+1,vector<ll>(A.begin()+l-1,A.end()));
ll offset=l-1;
for (int r=l;r<=N;++r) {
if (pi[r-offset]>0) {
continue;
}
dp[r]+=dp[l-1];
dp[r]%=mod;
}
}

下面是废掉的 AI 提示


P4391 [BalticOI 2009] Radio Transmission 无线传输

计算这个串的周期所使用的这个哈希做法。

首先呢,计数问题,还是要选择 dp 解决。

不过总体上来说,我们对 border 的概念不是很熟。

确实,这道题目的难点就在于,对于不同的划分,如果有相同的这个答案怎么办?这个时候就需要引入字符串算法。

众所周知,计数题目,必须要找到一种方法,一种特征,保证符合这一特征的划分方式/方案之间是独立,互不相同的。这道题目的特征如下:(注意,我们认为单一字符符合这个要求,毕竟递归需要有一终止条件嘛)

image

只要有前后缀相同情况,那么一定会有更加细粒度的切分方法,实现相同效果。

不过,如果只是需要无前后缀相同情况的话,那么直接判断一下前后缀第一个一不一样不就行了?事实上,我们要求,我们所选择的串,其所有子串(长度 ≥ 2)的前后缀都必须不同。

题目大意

题目描述

nn 篇博客,第 ii 篇博客按顺序提到了 lil_i 个用户,用数组 ai=[ai,1,ai,2,,ai,li]a_i=[a_{i,1},a_{i,2},\dots,a_{i,l_i}] 表示。

你需要将这 nn 篇博客全部发布。维护一个序列 QQ(初始为空)来记录最近提到的用户列表。你需要选择一个所有 nn 篇博客的发布顺序进行发布,每次发布一篇博客 ii 时,会对每一个 1jli1 \le j \le l_i 依次执行以下操作:

  • 如果 ai,ja_{i,j} 已经存在于 QQ 中,则将 ai,ja_{i,j} 移动到 QQ 的开头。

  • 否则,将 ai,ja_{i,j} 插入到 QQ 的开头。

求在发布所有 nn 篇博客后,所能得到的字典序最小的序列 QQ

输入格式

第一行包含一个整数 tt1t10001 \le t \le 1000),表示测试用例的数量。
每个测试用例第一行包含一个整数 nn1n30001 \le n \le 3000),表示博客数量。
接下来 nn 行,每行首先包含一个整数 lil_i1li30001 \le l_i \le 3000),表示第 ii 篇博客提到的用户数量,随后跟着 lil_i 个整数 ai,1,ai,2,,ai,lia_{i,1},a_{i,2},\dots,a_{i,l_i}1ai,j1061 \le a_{i,j} \le 10^6),表示提到的用户列表。
保证所有测试用例中 nn 的总和不超过 30003000li\sum l_i 的总和不超过 30003000

输出格式

对于每个测试用例,输出一行包含若干个整数,表示能够得到的字典序最小的 QQ

样例数据

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

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

样例解释

在第一个测试用例中,可以按如下顺序发布博客:

  1. 发布第一篇博客,QQ 变为 [6,4,3,2,1][6,4,3,2,1]

  2. 发布第三篇博客,QQ 变为 [3,2,9,1,6,4][3,2,9,1,6,4]

  3. 发布第二篇博客,QQ 变为 [1,5,2,3,9,6,4][1,5,2,3,9,6,4]

这里存在其他的发布方式,例如:

  1. 发布第三篇博客,QQ 变为 [3,2,9,1][3,2,9,1]

  2. 发布第一篇博客,QQ 变为 [6,4,3,2,1,9][6,4,3,2,1,9]

  3. 发布第二篇博客,QQ 变为 [1,5,2,6,4,3,9][1,5,2,6,4,3,9]

可以看到 [1,5,2,3,9,6,4][1,5,2,3,9,6,4] 的字典序比其他结果更小。如果我们不把第二篇博客放在最后发布,序列的第一个元素将不会是 11。因此 [1,5,2,3,9,6,4][1,5,2,3,9,6,4] 就是能得到的字典序最小的数组 QQ

在第二个测试用例中,可以按如下顺序发布博客:

  1. 发布第一篇博客,QQ 变为 [6,1][6,1]

  2. 发布第二篇博客,QQ 保持自身为 [6,1][6,1]

在第三个测试用例中,只能发布唯一的一篇博客,QQ 会变为 [1,6][1,6]

思路讲解

哎,其实这个思路和我一模一样,这个思路其实和我一模一样,我说白了你不会更加有更加简单的做法,实际上你就是这个做法,绷不住了。

也看了各路大神的代码,确实是没有更加简单的做法了。

1
2
3
4
5
6
7
8
9
10
11
12
while (!g.empty()) {
sort(all(g));
for (auto a:g[0]) {
ans.push_back(a);
used.insert(a);
}
vector<vector<ll>> new_g;
for (int i=1;i<g.size();++i) {
new_g.push_back(gen_uni(g[i]));
}
swap(new_g,g);
}

AC代码

AC
http://codeforces.com/contest/2205/submission/365031780

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

题目大意

题目描述

定义一个长度为 mm 的数组 bb 是“好的”,当且仅当不存在任何索引 ii1<i<m1 < i < m)满足 bi=max({bi1,bi,bi+1})b_i = \max(\{b_{i-1}, b_i, b_{i+1}\})

给定一个长度为 nn 的排列 aa。如果数组不是“好的”,你可以反复执行以下操作:
选择一个满足 ai=max({ai1,ai,ai+1})a_i = \max(\{a_{i-1}, a_i, a_{i+1}\}) 的索引 ii1<i<n1 < i < n)。然后,你可以从数组中删除 ai1a_{i-1} ai+1a_{i+1}。删除后,数组的左右两部分会重新拼接在一起。

求出使初始排列 aa 变为“好的”所需的最小操作次数。

输入格式

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

对于每个测试用例:
第一行包含一个整数 nn3n51053 \le n \le 5 \cdot 10^5),表示排列的长度。
第二行包含 nn 个互不相同的整数 a1,a2,,ana_1, a_2, \ldots, a_n1ain1 \le a_i \le n),表示初始的排列。

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

输出格式

对于每个测试用例,输出一个整数,表示使数组变为“好的”所需的最小操作次数。

样例

输入

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

输出

1
2
3
4
5
0
1
3
3
9

样例解释

在第一组测试用例中,数组初始时已经是“好的”,因此不能执行任何操作,答案为 00

在第二组测试用例中,可以进行如下操作:
选择索引 33,此时满足 a3=max({a2,a3,a4})a_3 = \max(\{a_2, a_3, a_4\})(即 3=max({1,3,2})3 = \max(\{1, 3, 2\}))。接着从数组中移除 a2a_2(元素 11)。数组变为 [4,3,2,5][4, 3, 2, 5]
此时数组已经是“好的”,因此答案为 11

在第三组测试用例中,可以进行如下操作:
选择索引 22。从数组中移除 a1a_1。数组变为 [5,3,6,2,1][5, 3, 6, 2, 1]
选择索引 33。从数组中移除 a2a_2。数组变为 [5,6,2,1][5, 6, 2, 1]
选择索引 22。从数组中移除 a1a_1。数组变为 [6,2,1][6, 2, 1]
通过上述 33 次操作,数组变为“好的”。

image

思路讲解

官方解法是这个笛卡尔树,不过我不太会这个东西,我们来看看其他做法吧。

https://www.luogu.com.cn/article/h4sddubz

这个 luogu 题解抓住了最大值一定不会被删除这个特性。(并不是删除最大值不优秀,而是重新阅读题面,你会发现)

我们最终采用的呢,是递归式求解做法啊,也就是分治做法,配合使用的那个ST表。

这个是利用了最大值一定不会被删除的这个特性,而且还利用了一个特性,就是只要这个最大值它不在L或者不在R,一定要把L旁边的或者R旁边的全部给删掉

1
2
3
4
5
6
7
8
9
10
auto solve=[&](auto && self,ll l,ll r) -> ll {
if (l>=r) {
return 0;
}
ll mx_i=st.query(l,r);
ll tmp1=self(self,l,mx_i-1);
ll tmp2=self(self,mx_i+1,r);
ll res=min(tmp1 + r-mx_i ,tmp2 + mx_i-l);
return res;
};

AC代码

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

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

C++ 14下,因为必须传入模板参数,嗯,可以这样子写其模板类型。

1
ST<ll,decltype(max_i)> st(N,vec_idx,max_i);

嗯,我们可以看到,嗯,这里应该是减L,不应该是减1。

1
2
3
4
5
6
7
8
9
10
auto solve=[&](auto && self,ll l,ll r) -> ll {
if (l>=r) {
return 0;
}
ll mx_i=st.query(l,r);
ll tmp1=self(self,l,mx_i-1);
ll tmp2=self(self,mx_i+1,r);
ll res=min(tmp1 + r-mx_i ,tmp2 + mx_i-l);
return res;
};

题目大意

题目描述
给定一个整数 nn,要求找到最小的正整数 kk,使得 nn 能够整除 knk^n(即 nnknk^n 的因数)。
数据保证在给定范围内始终存在答案。

输入格式
第一行包含一个整数 tt1t1001 \le t \le 100),表示测试用例的数量。
接下来的 tt 行,每行包含一个整数 nn2n1092 \le n \le 10^9),表示题目给定的数值。

输出格式
对于每个测试用例,输出一行一个整数,表示满足条件的最小正整数 kk

样例输入

1
2
3
4
5
4
8
12
369
55635800

样例输出

1
2
3
4
2
6
123
2090

样例解释
在第一个测试用例中(n=8n = 8):
k=1k = 1 时,18=11^8 = 188 不是 11 的因数;
k=2k = 2 时,28=2562^8 = 25688256256 的因数(因为 256=8×32256 = 8 \times 32)。
因此,最小可能的 kk22

在第二个测试用例中(n=12n = 12):
最小的 kk66,因为 1212612=21767823366^{12} = 2176782336 的因数(因为 2176782336=12×1813985282176782336 = 12 \times 181398528)。

思路讲解

不难发现,答案就是 N 的所有素因子的乘积。

不过对于我来说,一个难点是怎么样求,就是N的所有素因子的乘积是多少。(在这道题目的数据范围限制下)

我们这里就用到了一个小trick,就是一个数啊,大于根号N的素因子,有的话只有一个。因此我们就不断的把小的素因子全部都给除掉,那么剩下的一个素因子就是最大的了。(而且这个大于根号N的素因子显然不可能被乘很多遍)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ll opN=N;
for (auto p1:primes) {
if (p1*p1>N) {
break;
}
if (opN%p1==0) {
res*=p1;
while (opN%p1==0) {
opN/=p1;
}
}
}
res*=opN;
cout<<res<<"\n";

AC代码

AC

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

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