赛前模拟2025/8/28
:::epigraph[——__H_JM_\] 这绝对是我写过的最神奇的考试题目。 :::
Part 1 赛事纪录(大事祭)
[8:00]() 考场先开 T1,由于昨天写 T1 异常的顺利,因而我十分相信运气会顺延。
[8:30]() 想了 30 分钟,什么都没想出来(除了暴力,部分分),但在这时,我抬头一看,Asa_fish 竟然已经开始对拍了,内心慌张。
[8:40]() 写了一种特殊解,并借此发现了答案小于等于 3 的性质。
[8:50]() 写了一种神奇的做法,并开始对拍。
[9:00]() 开 T2。
[9:30]() T2 直接切掉了,并且开始写 T3。
[10:10]() 听到了旁边的 GYC 一阵欢呼,原来是他 T2 也做出来了。
[11:10]() 写完暴力后一直在想这道题 k=1 时的 DP 方程,费劲脑洞无法征服。
[12:00]() T4 写了一个贪心,写完后一侧大样利,才发现证伪了,还是写的特殊点。
[12:30]() 又检查了一会 T1。
Part 2 题目
T1
:::epigraph[——iChen] T1 都十分简单,如果写不出来,一定是题目在诈骗你 :::
::::info[我当时的考场想法,不想看的跳过]{open} 首先,答案不大于三,为什么呢?
:::info[证明]{open}
aaa|a|a
aaa|a|a
aaa|a|a
像图中这样分割,就算是最坏情况(图中)我们也最多是 3 :::
所以我当时的想法十分简单,既然这是一个万能方法,我直接特判不就是了吗?
可能是由于 Asa 的刺激,我虽然知道这是错的,仍然写了对拍
后来当然错了,于是我有想到了一个 "好办法"。
我直接大胆猜测不存在相同前缀长度超过 1 的情况,然后就这么 Ale ::::
首先我先假设你已经知道了前文中的那个重要结论。
然后
一个直接的思路是枚举
i, j 统计答案。考虑当前已经枚举了一个i ,如何找到最优的j 。对于b 的长度 < 3 的所有答案可以暴力枚举j ,只有O(1) 种。如果b 的长度 > 3,我们就不需要考虑j 的选取对a, b 字符串的影响,于是只考虑LCP(a, c) 和LCP(b, c) 的贡献。可以让
LCP(a, c) + LCP(b, c) = 0 当且仅当存在c_j \neq a_1 \land c_j \neq b_i 。否则:如果a_1 \neq b_i ,我们选j = n - 1 就有LCP(a, c) + LCP(b, c) = 1 ,最优;如果a_1 = b_i ,那后面的c_j 也都和它们相等,LCP(a, c) + LCP(b, c) \geq 2 ,还是选j = n - 1 最优。
没啥好说得了,我的方法相当于在他的基础上多枚举了一些,当然完全没有证明
:::success[AC code]{open}
#include <bits/stdc++.h>
using namespace std;
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
const int N=1e5+6;
int n;
int T;
int vis[27];
string a,b,c;
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
struct node{
int c[N];
void add(int x,int k){
for(int i=x;i<N;i+=(i&-i))
c[i]+=k;
}
int ask(int x){
int ans=0;
for(int i=x;i>0;i-=(i&-i))
ans+=c[i];
return ans;
}
}BIT[27];
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
signed main(){
cin>>T;
while(T--){
cin>>n;
cin>>a>>b>>c;
a=' '+a;
b=' '+b;
c=' '+c;
for(int i=0;i<26;i++)
memset(BIT[i].c,0,sizeof BIT[i].c);
for(int i=1;i<=n;i++){
BIT[b[i]-'a'].add(i,1);
}
int ANS=1e9;
for(int p=n;p>=3;p--){
for(int i=0;i<26;i++){
if(BIT[i].ask(p-1)-BIT[i].ask(1)>0){
ANS=min(ANS,(a[1]==(i+'a'))+(a[1]==c[p])+((i+'a')==c[p]));
}
}
}
cout<<ANS<<'\n';
}
return 0;
}
:::
T2
开局先看图
我们可以看一下样例中的 4 是如何出现的
这个图能够连接 (1-4),(1-5), 但为什么他们能连呢?
有两个条件:(x-y)
- x 连接的是自己的祖宗节点
- y 节点的儿子(路径上的)编号小于 x
所以直接用一个树状数组存储路径上的编号(除了 2)
:::success[AC code]{open} code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
const int N=2e5+5,Mod=1e9+7;
int n;
int ans;
int tot,head[N],ver[N<<1],nxt[N<<1];
struct node{
int c[N];
void add(int x,int k){
for(int i=x;i<N;i+=(i&-i))
c[i]+=k;
}
int ask(int x){
int ans=0;
for(int i=x;i>0;i-=(i&-i))
ans+=c[i];
return ans;
}
}BIT;
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
void add(int a,int b){
ver[++tot]=b;
nxt[tot]=head[a],head[a]=tot;
}
void dfs(int x,int fa){
ans+=BIT.ask(x-1);
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y==fa) continue;
BIT.add(y,1);
dfs(y,x);
BIT.add(y,-1);
}
}
int Pow(int x,int y){
int ans=1;
while(y){
if(y&1) ans=ans*x%Mod;
x=x*x%Mod,y>>=1;
}
return ans;
}
/*!@#$%^&*!@#$%^&*~~优美的分界线~~*&^%$#@!*&^%$#@!*/
signed main(){
cin>>n;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
add(a,b),add(b,a);
}
dfs(1,0);
cout<<Pow(2,ans)<<'\n';
return 0;
}
:::
T3
:::epigraph[——__H_J_M__]
这不是人做的,Maybe
:::
暴力
:::info[TJ(仅供参考,防止PDF)]
巡逻网络
k = 1
先考虑 k = 1,也即一维的情况。
整个题的贡献可以拆为三个部分:固定点内部互相的贡献、固定点与可选点之间的贡献、可选点内部互相的贡献。
第一种贡献是个定值,可以预处理出来;第二种贡献相当于在选择可选点的时候每个点会有一个额外权值,所以我们主要考虑第三部分,也即可选点内部之间的贡献如何处理。
考虑可选点,由于我们要求的是最大的曼哈顿距离和,且注意到绝对值本身就可以理解成最大值:
也就是说,绝对值比时无关紧要,我们只需要考虑安排好每个数每一维正负号的贡献就好了。
举个例子,假设已经选择了 m 个点,那么你可以先排序成
所以在一维的情况下,自然可以设一个 DP 出来:设
转移时,把第 i 个点放到第 p 个位置,贡献将会是
k = 2
其实本质上也没有什么区别,只是现在选择第 i 个点之后要同时考虑 x_i 和 y_i 的位置。
设
转移时,把第 i 个点的 x 坐标放到 p_1 的位置,y 坐标放到 p_2 的位置,贡献将会是
但是注意到,S_1 和 S_2 互相之间是有限制的,因为他们总需要保证出现的点数相同,不可能会是
这是
拓展
考虑一下有多次询问的情况,以及 k = 3.4 的情况怎么做? :::
T4
···
Part 3 展望未来
保T1T2,争T3T4。