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;
}