哈哈哈哈哈看了一眼 tutorial 的评论区好多人在喷前四题哈哈哈哈哈哈
题意简介
你有一条有 n 块木板的栅栏。这些木板原本的颜色分别是 (A_i),现在你希望把它们涂成 (B_i),为此你请来了一个祖宗师傅。这个师傅非常霸道,他每刷一次颜料,只会涂一块木板,并且刷了就一定要涂。他只刷 m 次,刷颜料的顺序还是固定的,如第 i 次刷的颜色是 (C_i),然后他会将某个木板的颜色涂改成 (C_i)。现问:如果你可以指定师傅每次涂哪个木板,你能否使最终的栅栏颜色序列变成 (B_i)?如果可以,输出师傅每次要涂哪个木板。
(感觉我这一翻译理解起来变复杂了)
简单说就是你需要把序列 A 改成序列 B,但是你只能依次修改 m 次,每次将任意位置的数字改成 (C_i),允许重复覆盖但是不允许跳过。问你是否可以达成目标,如果可以,输出 m 次修改的位置。
思路分析
跟 D 题一样的分类讨论+构造方案,冷静下来,多注意下细节,应该是能写的。本暴躁老哥就为了初始化把 m 打成 n 查了半小时。
首先,考虑什么情况下会输出 No。
- 某种颜色的操作数量不足。
- 操作数量是够的,但有一些多余的操作无处安放,会覆盖掉已经改好的位置。
自然的,我们会想到:去统计需要的颜色的种类和数量,与操作中出现的颜色的种类和数量进行对比。
(为了方便输出修改的位置,我们可以用 vector 或链表、邻接表之类存下这些颜色对应了哪些需要修改的位置。)
但是,并不是所有的操作都能恰好用上,总有一些操作是无效的,我们需要想办法处理这些多余的操作。
于是,我们自然想到,只要让它们被后面的有效的操作覆盖掉,或是浪费在与自己相同颜色的位置上就行了。(只要保证它们不会对最终成形的 B 产生影响即可)
具体的细节可以看代码。考虑仔细一点,查的耐心一点应该就没问题。
代码库
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e5+5;
int t,n,m,A[N],B[N],C[N],cnt[N],qnt[N]; int vis[N];
vector<int> Q[N];
int ans[N];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) vis[i]=0,Q[i].clear();
for(int i=1;i<=n;i++) scanf("%d",A+i),cnt[i]=qnt[i]=0;
for(int i=1;i<=m;i++) ans[i]=0;
for(int i=1;i<=n;i++){
scanf("%d",B+i);
if(B[i]!=A[i]) cnt[B[i]]++,Q[B[i]].push_back(i);
// cnt 表示某种颜色需要的数量 Q 用来存放这种颜色需要修改的位置
if(B[i]==A[i]) vis[A[i]]=i;
// vis 表示不需要修改的,可以用来覆盖掉多余的操作的位置
}
int mp=0,mlost=0;
// mp 记录可以确认修改位置的最后一个操作 mlost 则记录无法确认的最后一个操作
for(int i=1;i<=m;i++){
scanf("%d",C+i);
qnt[C[i]]++;
// qnt 表示某种颜色的操作的数量
if(cnt[C[i]]==0){
// 完全不需要的颜色只能覆盖掉
if(vis[C[i]]>0) ans[i]=vis[C[i]],mp=i;
else mlost=i; // 找不到该改哪,只能等后面覆盖在一个将会被覆盖的位置上
}else if(qnt[C[i]]<=cnt[C[i]]){
// 需求还在
mp=i;
ans[i]=Q[C[i]][qnt[C[i]]-1];
}else{
// 过剩的需求可以直接覆盖在已经被改好了的位置上 反正是同一个颜色
mp=i;
ans[i]=Q[C[i]][0];
}
}
bool fail=0;
for(int i=1;i<=n;i++) if(cnt[i]>qnt[i]){ fail=1; break; } // 某种颜色的需求没被满足
if(fail||mp<mlost){ puts("NO"); continue; } // mlost 的操作会制造多余的颜色破坏掉改好的序列
puts("YES");
for(int i=1;i<=m;i++) if(!ans[i]) ans[i]=ans[mp];
// 反正 mp 在后,那就让所有多余的操作指向 mp 会修改的位置就行了 这样 mp 会把它们覆盖掉
for(int i=1;i<=m;i++) printf("%d ",ans[i]);
puts("");
}
return 0;
}