题解:P12997 [GCJ 2022 #3] Revenge of GoroSort
wang_wen_zhe · · 题解
简要题意
给出一个长度为
思路及实现
一个显而易见的做法就是对排列进行循环分解,将同一个循环里的数分为一组。举个例子,排列
那将一个完全错排的排列随机打乱后期望的固定值是多少?这个问题相当于求一个完全随机的排列期望的固定值。先给结论,无论排列长度多少,期望总是
:::info[证明]
设
根据期望的线性性:
对于每个
:::
于是你就可以高高兴兴写一发代码交上去。
:::info[Code]
#include<bits/stdc++.h>
using namespace std;
int T,n,k;
int a[1051],c[1051];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>T>>n>>k;
while(T--)
{
while(true)
{
for(int i=1;i<=n;i++)
cin>>a[i];
int idx=0;
for(int i=1;i<=n;i++)
c[i]=0;
for(int i=1;i<=n;i++)
if(!c[i])
{
int x=i;
idx++;
do
{
c[x]=idx;
x=a[x];
}while(x!=i);
}
for(int i=1;i<=n;i++)
cout<<c[i]<<(i==n?"\n":" ");
cout.flush();
int k;
cin>>k;
if(k==-1) return 0;
if(k==1) break;
}
}
}
:::
然后发现只拿到了 18 分,那问题出在哪了?
很明显上面的代码的期望次数与排列中最长循环的长度有关,如果最长循环长度太长操作次数自然更多。解决方法也很简单,对每一组元素的个数做一个上限即可,取
下面给出代码实现,其实就多判断了一下每组元素个数。
:::success[AC Code]
#include<bits/stdc++.h>
using namespace std;
int T,n,k;
int a[1051],c[1051];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>T>>n>>k;
while(T--)
{
while(true)
{
for(int i=1;i<=n;i++)
cin>>a[i];
int idx=0;
for(int i=1;i<=n;i++)
c[i]=0;
for(int i=1;i<=n;i++)
if(!c[i])
{
int x=i;
idx++;
int tot=0;
do
{
c[x]=idx;
x=a[x];
tot++;
}while(x!=i&&tot<=10);
}
for(int i=1;i<=n;i++)
cout<<c[i]<<(i==n?"\n":" ");
cout.flush();
int k;
cin>>k;
if(k==-1) return 0;
if(k==1) break;
}
}
}
:::