2021/1/3训练

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=1ncgcd(i,n)
翻转的方案数为:
如果 n n n为奇数
方案数= n ∗ c ( n + 1 ) / 2 n*c^{(n+1)/2} nc(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} 2ncn/2+2ncn/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=1nngcd(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 1n 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=n1dnndnum[d]
现在我们考虑如何求出 n u m [ d ] num[d] num[d],即 1 − n 1-n 1n 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=n1dnndϕ(dn)
ϕ ( n d ) \phi(\frac{n}{d}) ϕ(dn)可以直接算。总的时间复杂度是 O ( t ∗ n 3 4 ) O(t*n^{\frac{3}{4}}) O(tn43)
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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值