首先造出所要求的得到的环。如果将位置一一对应上,答案就是不在所要求位置的人数。因为显然这是个下界,并且脑补一下能构造出方案达到这个下界。
剩下的问题是找到一种对应方案使错位数最少。可以暴力旋转这个环,然而是n2的。诶是不是特别熟悉……这好像很像卷积?然而好像没有什么优美的函数能方便的计算出两个排列的不匹配数,所以就别想NTT了。(是不是只有我这种弱智会往这上面想啊)
应该可以类似暴力的移动开头利用偏移量之类的来计算,然而容易被绕晕。注意到每个人向右移动到目标位置的最少次数之间的关系是不变的,相同的总是相同不同的总是不同,直接统计即可。
注意还可以将环翻转,需要再搞一次。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 50010 #define P 998244353 int n,a[N],b[N],q[N],cnt[N<<1],ans=0; bool flag[N]; void solve() { memset(cnt,0,sizeof(cnt)); for (int i=1;i<=n;i++) cnt[(q[i]-i+n)%n]++; for (int i=0;i<n;i++) ans=max(ans,cnt[i]); } int main() { #ifndef ONLINE_JUDGE freopen("1053.in","r",stdin); freopen("1053.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(); for (int i=1;i<=n;i++) a[i]=read(),b[i]=read(); int x=a[1],from=1;q[1]=1;flag[1]=1; for (int i=2;i<=n;i++) { if (flag[x]) {cout<<-1;return 0;} q[i]=x;flag[x]=1; if (a[x]==from) from=x,x=b[x]; else if (b[x]==from) from=x,x=a[x]; else {cout<<-1;return 0;} } if (x!=1) {cout<<-1;return 0;} solve(); reverse(q+1,q+n+1); solve(); cout<<n-ans; return 0; }