2020牛客暑期多校训练营(第五场) Bogo Sort

原题
题目描述
今天,Tonnnny学习了一种称为Bogo Sort的新算法。 老师给了Tonnnny Bogo Sort的代码:
2020牛客暑期多校训练营(第五场) Bogo Sort_第1张图片
老师说,函数shuffle 是等概率地随机排列长度为n的数组a,这个算法的期望复杂度为O(n⋅n!)。
但是,Tonnnny是一个坚定的男孩——他一点也不喜欢随机! 因此,Tonnnny改进了Bogo Sort。 他选择了一个最喜欢的长度为n的排列p,然后用排列p替换随机的shuffle,因此改进的算法,Tonnnny Sort,可以解决长度为n的数组的排序问题——至少Tonnnny如此认为。
2020牛客暑期多校训练营(第五场) Bogo Sort_第2张图片
Tonnnny对新算法感到满意,因此决定让您每天给他一个长度为N的不同数组,以使用Tonnnny Sort对其进行排序。
您是Tonnnny最好的朋友。 即使您发现该算法有某种错误,也希望让Tonnnny多快乐一会。 给定N和p,您需要计算Tonnnny可以开心的最大天数,因为在那之后,您将不能给Tonnnny一个可以用Tonnnny Sort排序的之前没出现过的数组。
答案可能非常大。 Tonnnny只喜欢最多N位的数字,因此请改为输出答案mod 10^N。
样例1
输入

5
1 2 3 4 5

输出

1

样例2
输入

6
2 3 4 5 6 1

输出

6

思路
本题考察的是置换群的知识。我们可以先把每个群所有的点数量求出来,再求出他们的最小公倍数即可。
因为本题的数据范围较大,所以要用高精度。因为高精度出发很容易出bug,所以我们可以用乘法代替除法。我们可以先把这些数的质数统计并累加起来,最后乘起来即可,具体过程可以看代码。
代码

#include
using namespace std;
const int maxn=1e5+5;
int n,l,r,cnt=1,ans,len=1,a[maxn],c[maxn],d[maxn],e[maxn],f[maxn],g[maxn],an[maxn]={0,1};
bool b[maxn];
void mul(int x)//大数乘
{
    for(int i=1;i<=len;i++) an[i]*=x;
    for(int i=1;i<len;i++)if(an[i]>9) an[i+1]+=an[i]/10,an[i]%=10;
    while(len<n&&an[len]>9) an[len+1]+=an[len]/10,an[len++]%=10;
    an[len+1]=0;
}
int main()
{
	for(int i=2;i<maxn;i++)if(!d[i]){for(int j=i*2;j<maxn;j+=i)d[j]=1;e[++ans]=i;}
	//素数筛求出质数
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)//求出每个置换群的点的个数,存在c数组中
	{
	    l=i,r=0;
		while(!b[l]) b[l]=1,r=1,c[cnt]++,l=a[l];
		if(r) cnt++;
	}
	for(int i=0;i<cnt;i++)//遍历质数
        for(int j=1,t=0;j<=ans&&c[i]>1;j++)//遍历每个c[i]含有这个质数
		{
            while(c[i]%e[j]==0)t++,c[i]/=e[j];
            f[e[j]]=max(f[e[j]],t);t=0;
        }
	for(int i=1;i<=ans;i++)while(f[e[i]]--)mul(e[i]);
	//把每个质数乘起来
	for(int i=len;i>=1;i--)printf("%d",an[i]);//反着输出
	return 0;
}

你可能感兴趣的:(2020牛客暑期多校训练营(第五场) Bogo Sort)