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

Bogo Sort

原题请看这里

题目描述:

今天, T o n n n n y Tonnnny 学习了一种称为 B o g o Bogo S o r t Sort 的新算法。 老师给了 T o n n n n y Tonnnny B o g o Bogo S o r t Sort 的代码:
在这里插入图片描述
老师说,函数 s h u f f l e shuffle 是等概率地随机排列长度为 N N 的数组 a a ,这个算法的期望复杂度为 O ( n n ! ) O(n⋅n!)
但是, T o n n n n y Tonnnny 是一个坚定的男孩——他一点也不喜欢随机! 因此, T o n n n n y Tonnnny 改进了 B o g o Bogo S o r t Sort 。 他选择了一个最喜欢的长度为 N N 的排列 p p ,然后用排列 p p 替换随机的 s h u f f l e shuffle ,因此改进的算法, T o n n n n y Tonnnny S o r t Sort ,可以解决长度为n的数组的排序问题——至少 T o n n n n y Tonnnny 如此认为。
在这里插入图片描述
T o n n n n y Tonnnny 对新算法感到满意,因此决定让您每天给他一个长度为 N N 的不同数组,以使用 T o n n n n y Tonnnny S o r t Sort 对其进行排序。您是 T o n n n n y Tonnnny 最好的朋友。 即使您发现该算法有某种错误,也希望让 T o n n n n y Tonnnny 多快乐一会。 给定 N N p p ,您需要计算 T o n n n n y Tonnnny 可以开心的最大天数,因为在那之后,您将不能给 T o n n n n y Tonnnny 一个可以用 T o n n n n y Tonnnny S o r t Sort 排序的之前没出现过的数组。答案可能非常大。 T o n n n n y Tonnnny 只喜欢最多 N N 位的数字,因此请改为输出答案 m o d mod 1 0 N 10^N

输入描述:

第一行包含一个整数 N N ( ( 1 1 \leq N N \leq 1 0 5 10^5 ) )
第二行包含 N N 个整数,表示一个 1 1 2 2 \cdots N N 的排列

输出描述:

T o n n n n y Tonnnny 满意的最大天数,取余 1 0 N 10^N

样例:

样例输入1:

5
1 2 3 4 5

样例输出1:

1

样例输入2:

6
2 3 4 5 6 1

样例输出2:

6

思路:

为啥牛客多校又出置换,这是牛客多校的特色嘛…
咳咳,一看到这道题,我就想到了多校第二场的J题,这题不就是那题的翻版嘛??????
本题就是置换群的一个应用,先求出所给序列的所有环的个数,然后求出环的周期数,题目要我们求出 1 n 1\sim n 的原数列经过多少次变换后会变回原数列,所以只要求出所有环的周期数的最小公倍数就可以了。
那么问题来了,这个数据范围的 l c m lcm 求出来可能会爆 l o n g l o n g longlong ! ! 所以本题还要使用高精度乘法来求解。
任意一对数,它们如果有质因子相同,那么根据 l c m = a b / g c d lcm=a∗b/gcd 可知,它会将公共的部分除掉,相当于对于每个质因子的个数求个 m a x max 即可。比如有质数 p r pr a a = p r 3 pr^3 ∗… b b = p r 5 pr^5 ∗… ,则它们的公共部分是 p r 3 pr^ 3 ,相乘之后有 p r 8 pr^ 8 ,除掉后有 p r 5 pr^ 5 也就是 p r m a x ( 3 , 5 ) pr^{max(3,5)} 。这样就可以避免高精度除法,只需要用高精乘低精就可以 A C AC
题目所说的取余操作嘛…根本就不会那么大,放出来打酱油的…

AC Code:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
int n,len=1,w,cnt;
int a[MAXN],v[MAXN],b[MAXN],pr[MAXN],pri[MAXN],ans[MAXN]={0,1};
void mul(int x)
{
    for(int i=1;i<=len;i++) ans[i]*=x;
    for(int i=1;i<len;i++) if(ans[i]>9) ans[i+1]+=ans[i]/10,ans[i]%=10;
    while(len<n&&ans[len]>9) ans[len+1]+=ans[len]/10,ans[len++]%=10;
    ans[len+1]=0;
}//高精度乘法:高精乘低精
int main()
{
	for(int i=2;i<MAXN;i++)
		if(!pri[i])
			{
				for(int j=i*2;j<MAXN;j+=i)
					pri[j]=1;
				pr[++cnt]=i;
			}//素数筛
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	for(int i=1;i<=n;i++)
		if(!v[i])
		{
			v[i]=b[++w]=1;
			for(int j=a[i];j!=i;j=a[j])
				v[j]=1,b[w]++;
		}//统计环的个数
	memset(pri,0,sizeof(pri));
	for(int i=1;i<=w;i++)
		for(int j=1,t=0;j<=cnt&&b[i]>1;j++)
		{
			while(b[i]%pr[j]==0){t++;b[i]/=pr[j];}
			pri[pr[j]]=max(pri[pr[j]],t);
			t=0;
		}
	for(int i=1;i<=cnt;i++)
		while(pri[pr[i]]--)
			mul(pr[i]);
	for(int i=len;i>=1;i--)
		printf("%d",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107583171