To_Heart—题解——Codechef Garden Game

题目链接

题解

题目大意

警长有 N N N个囚犯。囚犯们站成一行。给定一个长度为 N N N的置换 A A A。每次口哨后,当前处在第 i i i位置上的人会移动到 A i A_i Ai上。问至少多少次口哨后,所有人将会站在自己的初始位置上。

首先我们发现当 i i i号位的人回到起点的时候,第 A i A_i Ai位的人也会同时回到起点,那么此时 A A i A_{A_i} AAi也会同时回到起点。所以发现是一个环。
但是有可能环不止有一个,就比如以下的数据

6
3 4 5 6 1 2

此时我们发现 1 , 3 , 5 1,3,5 1,3,5 2 , 4 , 6 2,4,6 2,4,6分别构成了环,所以我们需要把这些环的长度去一个lcm。

然后就做完了。

我们做 lcm,暴力做时间复杂度卡满 O ( n 2 l o g n ) O(n^2logn) O(n2logn),但是不好卡qwq。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

bool f[100005];
ll a[100005];
ll sum[100005]={
    
    };
ll tot;
const ll Mod=1e9+7;
int n;

int DFS(int x){
    
    
	ll now=1;
	ll i=a[x];
	f[x]=1;
	while(i!=x){
    
    
		i=a[i];
		f[i]=1;
		now++;
	}
	return now;
}

ll Gcd(ll a,ll b){
    
    
	if(b==0)
		return a;
	return Gcd(b,a%b);
}

ll Pow(ll a,ll b){
    
    
	ll ans=1;
	while(b){
    
    
		if(b&1){
    
    
			ans*=a;
			ans%=Mod;
		}
		a*=a;
		a%=Mod;
		b>>=1;
	}
	return ans;
}

int main(){
    
    
	int T;
	cin>>T;
	while(T--){
    
    
		cin>>n;
		for(int i=1;i<=n;i++){
    
    
			scanf("%lld",&a[i]);
			f[i]=0;
		}	
		tot=0;
		for(int i=1;i<=n;i++){
    
    
			if(!f[i]){
    
    
				sum[++tot]=DFS(i);
			}
		}
		ll lcm=1;
		for(int i=1;i<=tot;i++){
    
    
			if(sum[i]!=1){
    
    
				for(int j=i+1;j<=tot;j++)
		    		sum[j]/=Gcd(sum[i],sum[j]);
		    	lcm=(lcm*sum[i])%Mod;
			}
		}
		printf("%lld\n",lcm);
	}
	
	return 0;
}

正解比较显然。
考虑将每个数的质因子拣出来,设个数为 c [ p r i m e ] c[prime] c[prime],则 lcm中此质数的个数为 max ⁡ ( c [ p r i m e ] ) \max(c[prime]) max(c[prime])。这里分解出来所有的 p r i m e prime prime 可以用 vector 存,时间复杂度: O ( n n + n l o g 2 ( n ) ) \mathcal {O(n\sqrt n+nlog_2(n))} O(nn +nlog2(n))

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define LL long long
using namespace std;
const int MAXN = 1e5 + 5, Mod = 1e9 + 7;
int T, n, a[MAXN], C[MAXN], c[MAXN], ans, mb, t;
int res;
bool vis[MAXN];
vector <int> v;
void dfs(int x, int depth) {
    
    
	vis[x] = 1;
	if(x == mb && depth) {
    
     ans = depth; return; }
	dfs(a[x], depth + 1);
}
int Max(int x, int y) {
    
     return x > y ? x : y; }
// nsqrt(n)+nlog(n)
int main() {
    
    
	scanf("%d", &T);
	while(T --) {
    
    
		scanf("%d", &n); memset(vis, 0, sizeof(vis)); res = 1;
		memset(C, 0, sizeof(C));
		for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
		for(int i = 1; i <= n; i ++) {
    
    
			if(vis[i]) continue;
			mb = i; ans = 0; dfs(i, 0); v.clear();
			for(int j = 2; j <= sqrt(ans); j ++) {
    
    
				while(ans % j == 0) ans /= j, c[j] ++;
				if(c[j]) v.push_back(j);
			}
			if(ans > 1) c[ans] ++, v.push_back(ans);
			for(int i = 0; i < v.size(); i ++) t = v[i], C[t] = Max(C[t], c[t]), c[t] = 0;
		}
		for(int i = 2; i <= 100000; i ++) for(int j = 1; j <= C[i]; j ++) res = (LL)res * i % Mod;
		printf("%d\n", res);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xf2056188203/article/details/118549906
今日推荐