当前位置: 代码迷 >> 综合 >> 【NOIP2005】篝火晚会
  详细解决方案

【NOIP2005】篝火晚会

热度:55   发布时间:2023-12-13 22:30:47.0

题目链接: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;
}

总结:虽然题目有点坑,不过还是不错的题。