4.3w+
社区成员
https://www.lanqiao.cn/problems/2139/learning/
先研究g函数的结果有哪些平方数构成,以g(8)为例,8个1的平方,4个2的平方,2个3~4的平方,1个5~8的平方,平方数个数的分布是一段一段区间,找到区间l和r的迭代规律。然后平方数求和利用公式去算,公式有除数,等价于乘上它的逆元。某段区间的平方数和为S(r) - S(l - 1)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 200;
const int M = 1e9 + 7;
ll ni6, ans;
ll get(int p) {
return (ll)p * (p + 1) % M * (2 * p + 1) % M * ni6 % M;
}
ll qmi(ll a, ll b, ll m) {
ll res = 1ll;
while (b) {
if (b & 1) res = res * a % m;
a = a * a % m;
b >>= 1;
}
return res;
}
void solve() {
ni6 = qmi(6, M - 2, M);
int n; cin >> n;
for (int l = 1, r; l <= n;) {
r = n / (n / l);
ans = (ans + (n / l) * ((get(r) - get(l - 1)) % M + M) % M) % M;
l = r + 1;
}
cout << ans;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
solve();
return 0;
}
题目大意是求出最小环的长度,图的特点是,每个点有且仅有一条出边。用带权并查集确定每个点的终点,如果某个点的传递对象的终点是自己,那么就形成了环。每次更新节点时候,维护该节点到父亲节点的路径长度。
#include<bits/stdc++.h>
using namespace std;
const int N = 200000 + 10;
int n, t, ans = 1000000007;
int fa[N], dis[N];
int get(int x)
{
if (x == fa[x]) return x;
int y = fa[x];
fa[x] = get(y);
dis[x] += dis[y];
return fa[x];
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= n; i++)
{
scanf("%d", &t);
int y = get(t);
if (i != y)
{
fa[i] = y;
dis[i] = dis[t] + 1;
}
else ans = min(ans, dis[t] + 1);
}
printf("%d", ans);
return 0;
}