Codeforces Round #717 (Div. 2)
D. Cut
题目大意:给定一个长度为n的数列,每次询问给定[L,R]区间,问最少将区间分成几个字段使每个子段的元素互质。
思路:
预处理:使用双指针维护对于每个下标
i
i
i,最长能延申到的右端点,记为
r
[
i
]
[
0
]
r[i][0]
r[i][0]。显然可以使用倍增处理出
r
[
i
]
[
j
]
r[i][j]
r[i][j],表示从下标
i
i
i开始分成
2
j
2^j
2j个子段能延申到的最大的右端点。
r[i][j] = r[r[i][j - 1]][j - 1]
查询询问:和倍增求LCA一样,不断接近终点但是不能超过,最后+1即可
for (int i = 19; i >= 0; i --)
{
if (r[l][i] <= r1)
{
l = r[l][i];
sum += (1 << i);
}
}
Codeforces Round #716
大致意思:从[1…n-1]中取尽量多的数,使他们乘积模n的余数为1
思路:根据裴蜀定理,要是模n的余数为1,取的数一定与n互质,因此我们取所有1…n-1中和n互质的数,如果最后得到的结果=1,那么直接输出取的数,如果!=1,那么得到的余数也一定和n互质,那么就是之前取的数,把那个数去掉即可。
D. Cut and Stick
大致意思:给定n个数,每次取下标为[l, r]的数,求区间出现次数大于区间长度一半的数。
思路:考虑使用可持久化权值线段树,每次求[l,r]区间时,一定是左子区间满足条件或右子区间满足条件,或者都不满足。因此递归即可。
Codeforces Round #715
E Almost Sorted
大致意思:给定长度为n的1-n的序列,满足
a
i
a_i
ai>=
a
i
−
1
a_{i-1}
ai−1 ,求字典序为k的排列是什么
考虑在1 2 3 …n中插入隔板
例如n=5时,原序列是1 2 3 4 5
1 2 | 3 4 | 5 => 2 1 4 3 5
1 | 2 3 4| 5 => 1 4 3 2 5
1 2 3 4 5 => 1 2 3 4 5
所有的满足条件的序列都满足这种性质。因此所有排列的总数即为
C
(
0
n
−
1
)
+
C
(
1
n
−
1
)
.
.
.
.
+
C
(
n
−
1
n
−
1
)
{0 \choose n-1}+C{1 \choose n-1}....+C{n-1 \choose n-1}
(n−10)+C(n−11)....+C(n−1n−1)=
2
n
−
1
2^{n-1}
2n−1
因此从前往后找到隔板进行翻转。
Educational Codeforces Round 107 (Rated for Div. 2)
D. Min Cost String
大致意思:只能用前k个拉丁小写字母,求一个含n个包含满足条件要求字母的串,满足(i,j) ,
a
i
=
=
a
j
a_i==a_j
ai==aj且
a
i
+
1
=
=
a
j
+
1
a_{i+1}==a_{j+1}
ai+1==aj+1的(i,j)最少。
思路:k个字母构成的{ a i a_i ai, a i + 1 a_{i+1} ai+1}最多有 k 2 k^2 k2种,因此考虑构造一个串,这个串包含 k 2 k^2 k2种情况,且都出现过一次,然后不断循环此串即可。
E. Colorings and Dominoes
大致意思:只能在o上染红色或者蓝色,
1
∗
2
1*2
1∗2的方块只能放在红色的o上,
2
∗
1
2*1
2∗1的方块只能放在蓝色的o上,求各种染色情况,每种染色情况能放最多方块的和。
思路:考虑连续的一串横着的或者竖着的oooo,他产生的贡献与其他o的颜色无关。为 ∑ \sum ∑ d p [ a n s ] ∗ 2 s u m − a n s dp[ans] * 2^{sum-ans} dp[ans]∗2sum−ans,其中ans为当前连续的o的个数,sum为总的o个数。因此问题变成如何求解 d p [ i ] dp[i] dp[i]
①:考虑第i位为1
1.第i-1位为0,那么产生的贡献就是 d p [ i − 2 ] dp[i-2] dp[i−2]
2.第i-1位为1,那么i,i-1位可以增添贡献,为 2 n − 2 + d p [ i − 2 ] 2^{n-2}+dp[i - 2] 2n−2+dp[i−2]。 分别为后两位1的贡献和前i-2位的贡献之和
②:考虑第i位为0
贡献即为dp[i-1]
因此 d p [ i ] = 2 ∗ d p [ i − 2 ] + d p [ i − 1 ] + 2 i − 2 dp[i] = 2 * dp[i - 2] + dp[i-1] + 2^{i-2} dp[i]=2∗dp[i−2]+dp[i−1]+2i−2
Codeforces Round #710 (Div. 3)
G. Maximize the Remaining String
大致意思:进行一系列操作,一次操作是可以删除字符串中一个出现两次及以上的字母,问最后能得到的最大字典序的字符串是什么
思路:记录每个数最后出现的次数,从前往后枚举,将前面已经枚举过的字母加入单调栈中,考虑当前字母时,如果当前字母已经出现过,那么跳过。否则,如果当前字母比单调栈的栈顶元素大,且栈顶元素在后面还会出现,那么弹出栈顶元素…不断操作,直到不满足条件,然后再把当前元素压入栈。然后枚举下一个元素。
Codeforces Round #712 (Div. 2)
E Travelling Salesman Problem
题目大意:给定n个点,每个点都有两个值
a
i
a_i
ai和
c
i
c_i
ci,点i到点j的边的权值为
m
a
x
(
a
j
−
a
i
,
c
i
)
max(a_j-a_i, c_i)
max(aj−ai,ci),求从点1开始,经过2-n点一次,最后回到1的最短路径。
思路一:提取出
c
i
c_i
ci,边的权值
w
=
c
i
+
m
a
x
(
a
j
−
a
i
−
c
i
,
0
)
w = c_i+max(a_j-a_i-c_i, 0)
w=ci+max(aj−ai−ci,0),取出
c
i
c_i
ci,即最小化
∑
\sum
∑
m
a
x
(
a
j
−
a
i
−
c
i
,
0
)
max(a_j-a_i-c_i, 0)
max(aj−ai−ci,0)
因此将
a
i
a_i
ai从小到大排序,若
i
>
j
i>j
i>j,则
i
−
>
j
i->j
i−>j的路径长度必定是0,否则是
m
a
x
(
a
j
−
a
i
−
c
i
,
0
)
max(a_j-a_i-c_i, 0)
max(aj−ai−ci,0)。假设原来的1点在目前
k
k
k的位置,可以证得,
k
−
>
1
−
>
n
−
>
k
k->1->n->k
k−>1−>n−>k一定是有一条最短路径,因此题目的最短路径等价于
a
1
a_1
a1到
a
n
a_n
an的最短路径。因此考虑建边,对于
j
>
i
j>i
j>i,如果
a
j
<
=
a
i
+
c
i
a_j<=a_i+c_i
aj<=ai+ci,那么从i向j连一条长度为0的边,如果
a
j
>
a
i
+
c
i
a_j>a_i+c_i
aj>ai+ci,易得最多从i向最小的j连一条长度为
a
j
−
a
i
−
c
i
a_j-a_i-c_i
aj−ai−ci的边,这样跑dijkstra即可。但是发现边数太多会超时,考虑优化。对于
j
>
i
j>i
j>i,如果
a
j
<
=
a
i
+
c
i
a_j<=a_i+c_i
aj<=ai+ci,那么从i向j连一条长度为0的边,这样会产生过多的边,考虑从
i
i
i向
j
j
j连一条长度为0的边,然后
j
j
j向
j
−
1
j-1
j−1连一条长度为0的边,等价于原来的建图方式。
思路二:还是按
a
i
a_i
ai排序后,从
1
到
n
1到n
1到n,考虑贪心,如果
i
<
j
i<j
i<j,有
a
j
+
c
j
a_j+c_j
aj+cj>
a
i
+
c
i
a_i+c_i
ai+ci,那么一定要从
i
i
i走到
j
j
j,代价为
m
a
x
(
a
j
−
a
i
−
c
i
,
0
)
max(a_j-a_i-c_i, 0)
max(aj−ai−ci,0)。如果不走的话,考虑
k
>
j
k>j
k>j,
i
−
>
j
i->j
i−>j代价为
m
a
x
(
a
k
−
a
i
−
c
i
,
0
)
max(a_k-a_i-c_i, 0)
max(ak−ai−ci,0)。
i
−
>
j
−
>
k
i->j->k
i−>j−>k代价为
m
a
x
(
a
k
−
a
j
−
c
j
,
0
)
+
m
a
x
(
a
j
−
a
i
−
c
i
,
0
)
max(a_k-a_j-c_j, 0) + max(a_j-a_i-c_i, 0)
max(ak−aj−cj,0)+max(aj−ai−ci,0)
可以得到第二种走法更好,因此每次每次更新
a
i
+
a
j
a_i+a_j
ai+aj,加上花费即可。
Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)
D Playlist
题目大意:从前往后遍历,如果到了n就回到1,如果有两个数的gcd=1,那么删除后面的那个数,直到所有数的gcd都!=1位置,输出删除数的个数,并且按删除的顺序输出数的位置。
思路:考虑一个数被删除后,只有它两边的数和周围的数的gcd会受到影响,其余的数不受影响。因此将数之间用双向链表建立,建立一个队列,存储需要删除的数对。每次删除一个数对时,需要判断其中一个数有没有被删掉。如果没有被删掉,则删掉后面那个,并且考虑加入相邻gcd=1的。
大致意思:将序列分为一系列子段,每一个子段的美丽度等于中间(
h
i
h_i
hi)最低的那个楼房的
b
i
b_i
bi,求
b
i
b_i
bi和的最小值。
考虑当前第i栋楼
①:是包括它的区间的
h
i
最
h_i最
hi最小值,那么这段区间的贡献就是
b
i
b_i
bi,所以从后往前枚举,找到第一个
h
j
<
h
i
h_j < h_i
hj<hi,那么
d
p
[
i
]
=
m
a
x
(
d
p
[
k
]
+
b
i
,
d
p
[
i
]
)
,
j
+
1
<
=
k
<
=
i
dp[i] = max(dp[k] + b_i, dp[i]),j + 1<=k<=i
dp[i]=max(dp[k]+bi,dp[i]),j+1<=k<=i。可以考虑用线段树优化。
②:包含在离他最近的比它矮的楼房的区间,设位置为j,则
d
p
[
i
]
=
m
a
x
(
d
p
[
i
]
,
d
p
[
j
]
)
dp[i] = max(dp[i], dp[j])
dp[i]=max(dp[i],dp[j])
因此最后的问题就是求 h j < h i , 满 足 j < i , 且 j 尽 量 大 h_j < h_i,满足j < i,且j尽量大 hj<hi,满足j<i,且j尽量大,这个就可以用单调栈做了。
Educational Codeforces Round 106 (Rated for Div. 2)
Codeforces Round #708 (Div. 2)
E2. Square-free division (hard version)
和E1一样,先把每个数字分解,这样就只需判断两个数字是不是相同。和E1的不同是。这题
k
>
=
0
k>=0
k>=0,因此可以设定一定数组。
l
[
i
]
[
j
]
l[i][j]
l[i][j]表示以下标
i
i
i为右端点,可以替换
j
j
j个数字,最多延申到的左端点。
因此可以采用dp做,
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示以i为右端点,替换了j个数字,最少划分的区间。f[i][j] = min(f[i][j], f[l[i][k] - 1][j - k] + 1);
0
≤
k
≤
j
0 \leq k \leq j
0≤k≤j
D. Genius
设
d
p
[
i
]
dp[i]
dp[i]为跳到i点时,最多获得的分数。i从1-n进行枚举,每次都可以从
1..
i
−
1
1..i-1
1..i−1跳到
i
i
i,假设从
j
j
j跳到
i
i
i之后
(
j
<
i
)
(j < i)
(j<i),可以再从
i
i
i跳回
k
k
k
(
k
<
j
)
(k < j)
(k<j),这样,每次更新dp,最后取最大的。
Codeforces Round #707 (Div. 2, based on Moscow Open Olympiad in Informatics)
D. Two chandeliers
题目大意:给定n,m,k随后n个不相同的
a
i
a_i
ai,m个不相同
b
i
b_i
bi,
a
i
,
b
i
a_i,b_i
ai,bi不停循环,问最少经过多少个数满足
a
i
和
b
i
a_i和b_i
ai和bi不同。
考虑对于数i,它在a中的位置是x,在b中的位置是y,假如他们会在位置pos
处相遇则
p
o
s
≡
x
(
pos\equiv x(
pos≡x(mod n
)
)
)
p
o
s
≡
y
(
pos\equiv y(
pos≡y(mod m
)
)
)
因为n,m不一定互质,所以考虑使用扩展中国剩余定理。本质上就是使用exgcd每次将两个式子合并成一个,得到pos的值。pos的通解就是
p
o
s
0
+
k
∗
l
c
m
(
n
,
m
)
pos_0 + k * lcm(n, m)
pos0+k∗lcm(n,m)。最后二分答案即可。
Codeforces Round #706 (Div. 2)
E Garden of the Sun
题目大意:起始给定一个矩阵,包含
X
和
.
X和.
X和.其中,X的周围8格都没有X。让你把一些.变成X,使得从任意X到其他X,只包含且必须包含一条简单的路径。
思路:构造题,可以将矩阵的1.4.7…3k+1行全部变成X,则对于3k+1,3k+4行,3k+2,3k+3必须有X连接这两行,且必须只有一条连接的竖线。因此只需要实现在这两行中加一条竖线,且不发生冲突即可。
Codeforces Round #705 (Div. 2)
D. GCD of an Array
题目大意:给定一个长度为n的数列和q次操作,每次操作将一个数乘x倍。
问每次操作后,序列的gcd是多少。
思路:考虑用一个multiset存储每一个质数在各个数中出现的次数。如果出现次数大于1的话就加入。每个操作更新multiset。只有当一个质数在muliset中出现了n次,那么当前质数对总的贡献就是multiset存储的最小值。
Educational Codeforces Round 105 (Rated for Div. 2)
主要是为了以后自己翻阅,因此写的不清楚
id:wuhu_captain,可以找到提交的代码