2021/1/3训练记录
HDU5495 LCS
可以任意交换a,b数组,即可以将所有环放一起。
a
n
s
=
n
−
环
个
数
(
环
长
度
不
为
1
)
ans=n-环个数(环长度不为1)
ans=n−环个数(环长度不为1)
所以就是如何快速找环了,这里我采用的并查集。AC代码如下
#include<bits/stdc++.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 2000000 + 10;
const int mod = 1e9 + 7;
int t, a[N], b[N], n,f[N];
int find(int x)
{
return f[x] == x ? x : f[x] = find(f[x]);
}
void init()
{
for (int i = 1; i <= n; i++)f[i] = i;
}
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
read(t);
while (t--)
{
read(n);
for (int i = 1; i <= n; i++)read(a[i]);
for (int i = 1; i <= n; i++)read(b[i]);
init();
int ans = n;
for (int i = 1; i <= n; i++)
{
if (a[i] == b[i])continue;
int x = find(a[i]);
int y = find(b[i]);
if (x == y)ans--;
f[x] = y;
}
printf("%d\n", ans);
}
return 0;
}
POJ 2409
题意是给你
n
n
n个珠串成一串,用
c
c
c种颜色去染色,问本质不同的串有多少个。两个串是本质一样的即其中一串可以通过旋转或者翻转来得到另一个串。
题解:polya定理
置换有旋转和翻转两种类型。
先考虑旋转方案数为:
∑
i
=
1
n
c
g
c
d
(
i
,
n
)
\sum_{i=1}^nc^{gcd(i,n)}
i=1∑ncgcd(i,n)
翻转的方案数为:
如果
n
n
n为奇数
方案数=
n
∗
c
(
n
+
1
)
/
2
n*c^{(n+1)/2}
n∗c(n+1)/2
如果为偶数
方案数=
n
2
∗
c
n
/
2
+
n
2
∗
c
n
/
2
+
1
\frac{n}{2}*c^{n/2}+\frac{n}{2}*c^{n/2+1}
2n∗cn/2+2n∗cn/2+1
其实就是找每一种置换的环数?
AC代码:
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<time.h>
#include<stdio.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
#define int long long
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int c, n;
int gcd(int x, int y)
{
return y ? gcd(y, x % y) : x;
}
int fpow(int x, int y)
{
int ans = 1;
while (y)
{
if (y & 1)ans = ans * x;
x = x * x; y >>= 1;
}
return ans;
}
signed main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
while (1)
{
read(c); read(n);
int ans = 0;
if (!c && !n)break;
for (int i = 1; i <= n; i++)
{
ans += fpow(c, gcd(n, i));
}
if(n&1)ans += n*fpow(c, (n + 1) / 2);
else ans += (n / 2)*fpow(c, n / 2)+ (n / 2) * fpow(c, n / 2+1);
printf("%lld\n", ans / (2 * n));
}
return 0;
}
P4980 【模板】Pólya 定理
洛谷的模板题,ykw又学会 (抄会)了一个省选难度的模板题。
关于Pólya 定理,可以看看这个博客这里
答案是
a
n
s
=
1
n
∑
i
=
1
n
n
g
c
d
(
i
,
n
)
ans=\frac{1}{n}\sum_{i=1}^{n}n^{gcd(i,n)}
ans=n1i=1∑nngcd(i,n)
式子还是非常简洁的,不过有个小问题是
n
n
n为
1
e
9
1e9
1e9级别的,
O
(
n
)
O(n)
O(n)是肯定不行的。
我们考虑枚举
n
n
n的因子
d
d
d,即枚举
g
c
d
(
i
,
n
)
=
d
gcd(i,n)=d
gcd(i,n)=d。假设
1
−
n
1-n
1−n中
g
c
d
(
i
,
n
)
=
d
gcd(i,n)=d
gcd(i,n)=d的个数为
n
u
m
[
d
]
num[d]
num[d],显然答案变成了
a
n
s
=
1
n
∑
d
∣
n
n
d
∗
n
u
m
[
d
]
ans=\frac{1}{n}\sum_{d|n}{n^d*num[d]}
ans=n1d∣n∑nd∗num[d]
现在我们考虑如何求出
n
u
m
[
d
]
num[d]
num[d],即
1
−
n
1-n
1−n中
g
c
d
(
i
,
n
)
=
=
d
gcd(i,n)==d
gcd(i,n)==d的个数。也即
g
c
d
(
i
d
,
n
d
)
=
=
1
gcd(\frac{i}{d},\frac{n}{d})==1
gcd(di,dn)==1的个数,也就是
ϕ
(
n
d
)
\phi(\frac{n}{d})
ϕ(dn)。所以我们的最终答案就是
a
n
s
=
1
n
∑
d
∣
n
n
d
∗
ϕ
(
n
d
)
ans=\frac{1}{n}\sum_{d|n}n^d*\phi(\frac{n}{d})
ans=n1d∣n∑nd∗ϕ(dn)
ϕ
(
n
d
)
\phi(\frac{n}{d})
ϕ(dn)可以直接算。总的时间复杂度是
O
(
t
∗
n
3
4
)
O(t*n^{\frac{3}{4}})
O(t∗n43)。
AC代码:
#include<bits/stdc++.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
#define int long long
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int t, n;
int phi(int x)
{
int ans = x;
for (int i = 2; i * i <= x; i++)
{
if (x % i)continue;
ans = ans - ans / i;
while (x % i == 0)x /= i;
}
if (x != 1)ans = ans - ans / x;
return ans;
}
int fpow(int x, int y)
{
int ans = 1;
while (y)
{
if (y & 1)ans = ans * x % mod;
x = x * x % mod; y >>= 1;
}
return ans;
}
signed main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
read(t);
while (t--)
{
read(n);
int ans = 0;
for (int i = 1; i * i <= n; i++)
{
if (n % i)continue;
int d = i, k = n / i;
ans = (ans + fpow(n, d) * phi(k)%mod)%mod;
if(k!=d)
ans = (ans + fpow(n, k) * phi(d) % mod) % mod;
}
printf("%lld\n", ans*fpow(n,mod-2)%mod);
}
return 0;
}

294

被折叠的 条评论
为什么被折叠?



