题目链接:https://www.luogu.org/problemnew/show/P1053
题目巨坑!!
首先要注意bi不是连续的。
然后不难发现最少的总代价就是目标环和初始环不匹配的个数
之后30分的做法就是枚举每一个断点,一一判断不匹配的个数。
100分做法:
联想手链:如果有一些珠子,它们在第一次数珠子的时候离目标位还有x个珠子,那么下一次离目标就会还有x-1格。那么它们要么同时对上,要么同时对不上。所以我们只需随便拆一下,然后统计相同的珠子之间距离出现次数的最大值,用n减去即得到答案。
还有几个比较麻烦的地方:
建环
统计距离时的转化(取模或者特判都可以)
code:
#include<iostream>
using namespace std;
const int N=5e4+10, INF=0x3f3f3f3f;
int num, ans, an[N], bs[N], s1[N], s2[N], n[N], s[N], cnta[3*N], cntb[3*N];
int main() {
cin >> num;
for (int i=1; i<=num; i++)
cin >> s1[i] >> s2[i];
for (int i=1; i<=num; i++) {
if ((s1[s1[i]]!=i&&s2[s1[i]]!=i) || (s1[s2[i]]!=i&&s2[s2[i]]!=i)) {
cout << "-1";
return 0;
}
}
//按照顺时针和逆时针分别建环
n[1]=s1[1], s[1]=s2[1];
int ntmp=n[1], nlast=1, slast=1, stmp=s[1];
for (int i=2; i<=num; i++) {
n[ntmp]=(nlast==s1[ntmp])?s2[ntmp]:s1[ntmp];
s[stmp]=(slast==s1[stmp])?s2[stmp]:s1[stmp];
nlast=ntmp;
slast=stmp;
ntmp=n[ntmp];
stmp=s[stmp];
}
an[1]=1, bs[1]=1;
for (int i=2; i<=num; i++) {
an[i]=n[an[i-1]];
bs[i]=s[bs[i-1]];
}
int tmp=-INF, tmpa, tmpb;
//统计,这里是特判的
for (int i=1; i<=num; i++) {
if (an[i]-i<0) {
cnta[an[i]-i+num]++;
tmpa=cnta[an[i]-i+num];
}
else {
cnta[an[i]-i]++;
tmpa=cnta[an[i]-i];
}
if (bs[i]-i<0) {
cntb[bs[i]-i+num]++;
tmpb=cntb[bs[i]-i+num];
}
else {
cntb[bs[i]-i]++;
tmpb=cntb[bs[i]-i];
}
tmp=max(max(tmpa, tmpb), tmp);
}
ans=num-tmp;
cout << ans;
return 0;
}
总结:虽然题目有点坑,不过还是不错的题。