2023年2月5日10:29:30
update 2023年2月27日18:30:09
刷题随记 \color{LightPink}刷题随记 刷题随记
ABC
ABC 288
Abc288 C
用dfs找非树边。(没想到连通块这回事)
Abc 288D
看出来化成差分,以modk余数分成k组,只跟组内数的和有关
,但是Wa 了两次,应为有两个点
{
-
和 (y + 1) mod k 同余的那一组不用考虑
-
和首项同余的那一组和,必须是原数组a[]中 a[x - 1] 的相反数(要保证全为零)
}
其实这次原本以为会排两千多名的。。。
Abc288F
主代码如下
dp[0]= s[0] - '0';
f[0]= 1;
for(int i = 1; i < n; i++) {
dp[i]= (dp[i - 1] * 10 + f[i - 1] * (s[i] - '0')) % mod;
f[i]= (f[i - 1] + dp[i - 1]) % mod;
dp[i]= (dp[i] + dp[i - 1] * (s[i] - '0')) % mod;
}
//dp i 到i结尾的字符串的贡献
// 考虑暴力转移是 O ( n 2 ) O(n^2) O(n2) dp[i] = ∑ j = 0 i − 1 \sum^{i - 1}_{j = 0} ∑j=0i−1 dp[j] * num(j+1 ~ i)
// 注意到 i 加入有两种方法,一是接上末尾,二是以乘号相隔
//dp[i] = dp[i - 1] * a[i] 乘号相隔
//dp[i] += f(i - 1) * a[i] + dp[i - 1] * 10 接上末尾
//f[i] 是 形似A * B * C 中的 A* B 接上末尾后,f[i] += dp[i -1]
Abc 288E
这道题我想了dp方程想了好久。。。
去掉x[i]必须买的限制, dp[i][j] 表示前i个买了j个的最小花费
转移很好想 dp[i][j] = min(dp[i- 1][j], dp[i - 1][j– 1] + a[i] + cst[i][i – (j – 1)];
然后加上x[i]必须买的限制,就相当于遇到 x[i] 就把dp第一个转移去掉。
Abc 288G``
可以看出,最优答案一定落在 B i + C j B_i + C_j Bi+Cj上, 考虑将B递减排序
对于每一个C 有 A n s = i ∗ ( B i + C ) = i ∗ C + i ∗ B i Ans = i * (B_i + C) = i * C + i * B_i Ans=i∗(Bi+C)=i∗C+i∗Bi
没思路了,看了群里,知道是关于函数的,之后,我也把这幅图找来了,方便理解
从
B
1
到
B
n
B_1 到B_n
B1到Bn 每一条直线K递减, B递增,考虑每一条直线管辖的区间左端点
D
i
也是单调递增的
D_i 也是单调递增的
Di也是单调递增的 我做法是单调队列(不会凸包,不会半品面交)
for (int i = 2; i <= n; i++) {
while(0 < r && a[i] - a[q[r]] > d[r] * (q[r] - i)) r--;
q[++r] = i;
if (r>1) d[r] = (a[i] - a[q[r - 1]] + q[r - 1] - i - 1) / (q[r - 1] - i);
else d[r] = 0;
d[r] = max(d[r], 0LL);
}
这样就能把有用的直线筛出来,最后离线询问再做一次单调队列找出答案就行了,
注意取整时的误差
又被出题人拿捏了
ABC 289
Abc 289F
这题我交了七次,前四次被handmake卡住,后两次是被big random卡住(感觉被人改过),最后还是推理数据后特判A过,至于为什么RE,我还没想到。(upd:我现在知道了)
可以分别考虑横纵坐标。 首先不难观察出一个条件,起点终点差为偶数,
考虑连续翻折,最终坐标是 ∑ i = 1 n ( − 1 ) i + 1 2 x i + ( − 1 ) n S \sum_{i = 1}^{n}(-1)^{i+1}2x_i + (-1)^nS ∑i=1n(−1)i+12xi+(−1)nS;
我就想着将两次跳跃合并为一次,应为1e6次操作管够,上限应该是8e5。
最后就是怎么将横纵坐标操作数保持一致,这个方法很多…(话说我的好像有点复杂,但貌似是路径最短的做法
(赛时A出人数300多,比G还少。。。还是第一次做出300左右的题)
ABC 289E
总状态数N^2,bfs就行了
ABC 289 D 直接背包dp
Abc 290
A 用桶模拟即可
B 前K个o保留,其余全x
C 排序后找mex ,有k次机会补数
D 观察到在Lcm(n, d) 处会相遇一次, 即每 Lcm(n, d) / d 次会相遇一次
l c m ( n , d ) / d = n ∗ d / g c d ( n , d ) / d = n / g c d ( n , d ) lcm(n, d) / d = n * d / gcd(n, d) / d = n / gcd(n, d) lcm(n,d)/d=n∗d/gcd(n,d)/d=n/gcd(n,d)理解这个答案就不难出来了
E 考虑将 f ( x ) f(x) f(x) 拆成每个pair(x, y) 的贡献
Ans = ∑ x ∑ y , y > x [ a [ x ] ! = a [ y ] ] ∗ m i n ( x , n − y + 1 ) \sum_x\sum_{y, y > x}[a[x] != a[y] ] * min(x, n - y + 1) ∑x∑y,y>x[a[x]!=a[y]]∗min(x,n−y+1)我第一直觉是树状数组拆系数,之后就这么写了,没想到双指针啥的
F 设节点为n, 不难得出总度数为2n-2(一条边贡献两次),
然后观察出diameter 的max 为
n
u
m
o
f
x
d
e
g
r
e
e
>
=
2
num \ of \ x_{degree}>=2
num of xdegree>=2设有K个度数大于一的节点
A
n
s
=
∑
k
=
1
n
−
2
C
n
−
3
k
∗
C
n
k
∗
k
Ans = \sum_{k=1}^{n-2}C_{n-3}^{k}*C_{n}^k*k
Ans=∑k=1n−2Cn−3k∗Cnk∗k这个做法是O(Tn) 的,考虑优化对于上面这个式子, 分离k 的干扰,变成int ans = (n + 1) * calc(2 * n - 3, n - 2) % mod - n * calc(2 * n - 4, n - 2) % mod;
原谅我不想打latax了
G ,,, 实在不想说什么了,真心good 题
ARC
ARC155
ARC155_a
不难发现, 1 的个数要么+2,-2所以总数必须是偶数
记个数为K
K = 0 || K > 2 步数直接为 k / 2;
k == 2 不相邻则步数为1
考虑以下三种corner s = “0110” “011” “110”
至此,本题做完
ARC156_b
首先观察出第k步写x, 那么0,到 x - 1必须都有, 钦定最后一步写x
总步数k, 必须步数k - cnt - 1 (cnt 为
0
t
o
x
−
1
0 \ to \ x - 1
0 to x−1 中原数组没有的数的个数)
剩下的便是自由元
之后就是经典的计数
C
k
−
c
n
t
−
1
+
x
+
1
−
1
x
+
1
−
1
C_{k - cnt - 1 + x + 1 - 1} ^ {x + 1 - 1}
Ck−cnt−1+x+1−1x+1−1 =
C
k
−
c
n
t
+
x
−
1
x
C_{k - cnt + x - 1}^{x}
Ck−cnt+x−1x
枚举即可
Arc 157
Introduction 本来想用overleaf写的, 不会插入代码, 放弃了
A
一开始是考虑 s = “XX” , 然后将剩下的X, Y 插入其中, 发现 “XY” “YX” 的个数相差不会大于一
然后考虑枚举收尾字母是什么, 之后就发现可能没有一个“X”, 就假了
然后发现 “XYX” 和 “YXY”, 可以将X, Y 插入其中
代码
if (abs(a[2] - a[3]) > 1 || (!a[2] && !a[3]) && (a[1] && a[4])) {
cout << "No" << endl;
} else cout << "Yes" << endl;
B
贪心,细节有点多, 有趣的是 如果
K
K
K 有剩余的话 可以
{
k = n - k, x ->y, y-> x
}
然后就归化到一种情况了
C
考虑将如果新增一组 YY, 到当前点的路径贡献 变成
(
x
1
+
1
)
2
+
(
x
2
+
1
)
2
+
.
.
.
+
(
x
n
+
1
)
2
(x_1 + 1)^2 + (x_2 + 1) ^ 2 + ... + (x_n + 1) ^ 2
(x1+1)2+(x2+1)2+...+(xn+1)2
$ ==> $
x
1
2
+
2
x
1
+
1
+
.
.
.
x
n
2
+
2
x
n
+
1
x_1^2 + 2x_1 + 1 + ... x_n^2 + 2x_n + 1
x12+2x1+1+...xn2+2xn+1
用三个vec分别维护二次, 一次,常数项就好了
初始化 起点一次项为1,其余为零
CF 1799
A
直接模拟, 当时有点慌,居然写了十五分钟
B
首先看到 操作上限 操作上限 操作上限是30n, 而 l o g 2 1 0 9 log_210^9 log2109<30 之后就可以做了
C
还是观察, 考虑将最小字母一个放前一个放后这样放
可是
- abbc -> bbca 而不是 bcba
问题在于一个字符是奇数个, 所以放在前面的时候直接导致了后缀无论怎么放都>前缀
所以把这个字符放前面, 剩下的倒顺序放好就行了
还有个问题,就是
- abb -> bab 而非 bba 所以, 只剩两种字母的情况要将那个夹在中间。