【题解】arc189_c Balls and Boxes
arc189_c Balls and Boxes
题意
给定 \(n\) 个位置,第 \(i\) 个位置有 \(a_i\) 个红球和 \(b_i\) 个蓝球。
再给定整数 \(x\) 和长度为 \(n\) 的排列 \(p,q\)。
可以进行如下操作任意次:
-
选择一个位置 \(i\)。
-
将 \(i\) 位置的所有红球放到位置 \(p_i\)。
-
将 \(i\) 位置的所有蓝球放到位置 \(q_i\)。
问能否把所有球都放到位置 \(x\),如果能,输出最小操作次数。
如果不能,输出 -1。
题解
知识点:动态规划。
将 \(i\) 向 \(p_i\) 连有向边,就得到了红球的路径图。
同理,将 \(i\) 向 \(q_i\) 连有向边,就得到了蓝球的路径图。
由于是排列,所以得到的图是若干个环。
容易发现,有解当且仅当所有篮球和红球都在 \(x\) 所在的那个环。
从 \(u\) 开始,跳 \(p_u\) 碰到的第一个 \(a_u=1\) 的位置,这是离 \(u\) 最远的红球,所以红球的路径就是从这个位置一直跳 \(p_u\) 跳到 \(u\) 组成的序列去掉 \(u\),设长度为 \(l_1\)。
蓝球的处理同理,设长度为 \(l_2\)。
与注意到一次操作是同时将蓝球红球同时拿出去的,要使得操作次数尽可能少,就要让蓝球红球一同操作的位置尽可能多,也就是两类球路径序列的 LCS(最长公共子序列),记为 \(res\),则答案为 \(l_1+l_2-res\)。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 202506
// #define int long long
int n,p[N],q[N],s,f[N];
bool a[N],b[N];
int l1,l2,a1[N],a2[N];
inline bool chk(){
int sa=accumulate(a+1,a+1+n,0),res;
int sb=accumulate(b+1,b+1+n,0),u;
u=s;
res=0;
do{
res+=a[u];
u=p[u];
}while(u!=s);
if(res!=sa){
return 0;
}
u=s;
res=0;
do{
res+=b[u];
u=q[u];
}while(u!=s);
if(res!=sb){
return 0;
}
return 1;
}
struct bit{
#define lb(x) (x&-x)
int tr[N];
inline void upd(int k,int d){
while(k<=n){
tr[k]=max(tr[k],d);
k+=lb(k);
}
}
inline int ask(int k){
int ans=0;
while(k){
ans=max(ans,tr[k]);
k-=lb(k);
}
return ans;
}
}t;
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>s;
rep(i,1,n){
cin>>a[i];
}
rep(i,1,n){
cin>>b[i];
}
rep(i,1,n){
cin>>p[i];
}
rep(i,1,n){
cin>>q[i];
}
if(!chk()){
cout<<"-1";
return 0;
}
int u;
bool suc;
u=p[s];
suc=0;
while(u!=s){
if(a[u]){
suc=1;
}
if(suc){
a1[++l1]=u;
}
u=p[u];
}
u=q[s];
suc=0;
while(u!=s){
if(b[u]){
suc=1;
}
if(suc){
a2[++l2]=u;
}
u=q[u];
}
int ans=l1+l2;
rep(i,1,l1){
f[a1[i]]=i;
}
rep(i,1,l2){
if(!f[a2[i]]){
continue;
}
int res=t.ask(f[a2[i]])+1;
t.upd(f[a2[i]],res);
}
cout<<ans-t.ask(n);
return 0;
}

浙公网安备 33010602011771号