Problem - 1833E - Codeforces
有 n 个人来到一个节日并决定跳几个“圆舞”。每个圆舞至少有 2 个人,且每个人恰好有两个邻居。如果圆舞中只有 2 个人,则它们在两侧拥有相同的邻居。
你想要确定有多少个“圆舞”可以跳。但是每个参与者只记得一个邻居。你的任务是确定最小和最大的“圆舞”数量。
例如,如果假日上有 6 个人,他们记得的邻居编号都相同 [2,1,4,3,6,5],那么最小圆舞数量为 1:
1−2−3−4−5−6−1
最大圆舞数量为 3:
1−2−1
3−4−3
5−6−5
输入:
第一行包含正整数 t(1≤t≤104),表示测试用例的数量。以下是测试用例的描述。
对于每个测试用例,第一行包含正整数 n(2≤n≤2⋅105),表示假日上的人数。
对于每个测试用例,第二行包含 n 个整数 ai(1≤ai≤n,ai≠i),表示第 i 个人记得的邻居编号。
保证测试用例正确,并且对于至少一种人员分组,测试用例是正确的。
保证所有测试用例中 n 的总和不超过 2⋅105。
Example
Input
Copy
10
6
2 1 4 3 6 5
6
2 3 1 5 6 4
9
2 3 2 5 6 5 8 9 8
2
2 1
4
4 3 2 1
5
2 3 4 5 1
6
5 3 4 1 1 2
5
3 5 4 1 2
6
6 3 2 5 4 3
6
5 1 4 3 4 2
Output
Copy
1 3 2 2 1 3 1 1 1 2 1 1 1 1 2 2 1 2 1 1
题解:
对于相邻的人,我们可以看做他们之间连了一条链,
图大概有这两种情况,因为每个人最多和两个人链接,题中保证了所给数据的准确性
对于第二种情况,这种环相当于每个人相邻两边都有人,不会有其他人再加入了
而对于第一为一条链,那么我们可以与其他链链接
最多情况是每个联通块都不连接,就是联通块的数量
最少情况就是把所有链链接 + 环的数目
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define int long long
typedef pair<int,int> PII;
typedef unsigned long long ULL;
const int N = 4e5 + 10;
int mod = 1e9 + 7;
set<int> s[N];
vector<int> p[N];
int st[N];
int du[N];
int dfs(int u)
{
st[u] = 1;
int f = du[u] == 2;
for(auto ne:p[u])
{
if(st[ne])
continue;
f &= dfs(ne);
}
return f;
}
void solve()
{
int n;
cin >> n;
for(int i = 1;i <= n;i++)
{
int x;
cin >> x;
if(!s[i].count(x))
{
s[i].insert(x);
s[x].insert(i);
p[x].push_back(i);
p[i].push_back(x);
du[i] ++;
du[x] ++;
}
}
int cnt1 = 0,cnt2 = 0;
for(int i = 1;i <= n;i++)
{
if(!st[i])
{
if(dfs(i))
{
cnt1++;
}
else
{
cnt2++;
}
}
}
cout << cnt1 + (cnt2 > 0) <<" "<<cnt1 + cnt2 <<"\n";
for(int i = 1;i <= n;i++)
{
s[i].clear();
p[i].clear();
du[i] = 0;
st[i] = 0;
}
}
signed main()
{
ios::sync_with_stdio(0 );
cin.tie(0);cout.tie(0);
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}