Link with Limit

题目链接

定义: f n ( x ) = f ( f n − 1 ( x ) ) f_n(x)=f(f_{n-1}(x)) fn(x)=f(fn1(x)),给定 f 1 ( x ) f_1(x) f1(x),现定义一函数 g ( x ) , g ( x ) = lim ⁡ n → ∞ 1 n ∑ i = 1 n f i ( x ) g(x),g(x)=\lim_{n \to \infty} {1 \over n}\sum_{i=1}^{n}{f_i(x)} g(x),g(x)=limnn1i=1nfi(x),问是否对于所有的 x x x,都有 x = g ( x ) x=g(x) x=g(x)

易知(反证)至少存在一个这样的集合,集合内的元素满足 f n ( x ) = y , f n − 1 ( y ) = z , f n − 2 ( z ) = x f_n(x)=y,f_{n-1}(y)=z,f_{n-2}(z)=x fn(x)=y,fn1(y)=z,fn2(z)=x这样的内部循环,而不再这种集合内的元素,也可以通过多次 f n ( x ) = f ( f n − 1 ( x ) ) f_n(x)=f(f_{n-1}(x)) fn(x)=f(fn1(x))关系与这些集合中的一个元素产生联系,当产生联系后, f n ( x ) = f ( f n − 1 ( x ) ) f_n(x)=f(f_{n-1}(x)) fn(x)=f(fn1(x))使得它的值在这个集合中循环,所以当 n → ∞ n \to \infty n时, g ( x ) , g ( x ) = lim ⁡ n → ∞ 1 n ∑ i = 1 n f i ( x ) = ∑ 对 应 集 合 的 所 有 元 素 之 和 对 应 集 合 的 元 素 个 数 g(x),g(x)=\lim_{n \to \infty} {1 \over n}\sum_{i=1}^{n}{f_i(x)}={\sum对应集合的所有元素之和 \over 对应集合的元素个数} g(x),g(x)=limnn1i=1nfi(x)=,所以如果满足所有 x = g ( x ) x=g(x) x=g(x),则所有集合的平均值相等

ps:注意精度问题, a b = c d ⇒ a ∗ d = b ∗ c {a \over b}={c \over d} \Rightarrow a*d = b*c ba=dcad=bc,采用乘法比较

AcCode:

//#pragma GCC optimize(2)
//#pragma comment(linker,"/STACK:1024000000,1024000000")

#include <iostream>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstdio>
#include <vector>
#include <fstream>
#include <cmath>

#define pint std::pair<int,int>
#define in std::cin
#define out std::cout
#define SYNC std::ios::sync_with_stdio(false);

const int N = 2e5 + 10;

std::vector<pint> ans;
int cnt[N];
int edge[N];

inline void getAns(int rt, int sum, int num, int p) {
	if (rt == p)  ans.push_back(std::make_pair(sum, num));
	else getAns(edge[rt], sum + edge[rt], num + 1, p);
}

inline void dfs(int rt, int rem) {
	cnt[rt] = rem;
	if (cnt[edge[rt]] == rem) getAns(edge[rt], edge[rt], 1, rt);
	else if (cnt[edge[rt]] == 0) dfs(edge[rt], rem);
}

signed main() {
	SYNC;
	//std::ifstream in("input.txt");
	//std::ofstream out("out.txt", std::ios::out);
	//if (!in.is_open()) {
	//	std::cout << "error!" << std::endl;
	//	return 0;
	//}
	int t; in >> t;
	while (t--) {
		ans.clear();
		int n, rem = 0; in >> n;
		for (int i = 1; i <= n; i++)  cnt[i] = 0;
		for (int u = 1; u <= n; u++) { in >> edge[u]; if (u == edge[u]) rem++; }
		if (rem > 1) { out << "NO\n"; continue; }
		for (int i = 1, num = 1; i <= n; i++) if (!cnt[i]) dfs(i, num++);
		bool flag = true;
		for (int i = 0; i < ans.size() - 1; i++) if (ans[i].first * ans[i + 1].second != ans[i].second * ans[i + 1].first) { flag = false; break; }
		if (flag) out << "YES\n";
		else out << "NO\n";
	}
	//if (in.eof()) std::cout << "OK!\n";
	//in.close();
	//out.close();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值