AtCoder Regular Contest 114(A-C)

A - Not coprime

题意:已知\(N\)个数字不超过50,找到最小的数字与这\(N\)个数字不互素
题解:知\(1-50\)的素数一共有15个,故答案一定是这15个素数组合的乘积。故枚举这些组合。
代码如下:

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int NMAX = 2e5 + 10;
const int MOD = 1e9 + 7;
 
int a[50];
int prime[50], isw[50], tot;
void init()
{
	for(int i = 2;i < 50;i++)
	{
		if(!isw[i])  prime[++tot] = i;
                for(int j = 1;j <= tot;j++){
                    if(i * prime[j] >= 50)    break;
                    isw[i*prime[j]] = 1;
                    if(i % prime[j] == 0)   break;
                }
	}
}
int main(int argc, char const *argv[])
{
	int n;
	init();
	scanf("%d",&n);
	for(int i = 1;i <= n;i++)
		scanf("%d", a+i);
	ll ans = (1ll<<63)-1, ant;
	for(int i = 1;i < 1<<15;i++)
	{
		bool flag = true;
		ant = 1ll;
		for(int j = 0;j < 15;j++)
			if((i>>j) & 1)
				ant *= prime[j+1];
		for(int j = 1;flag && j <= n;j++)
			if(__gcd(1ll*a[j], ant) == 1ll)
				flag = false;
		if(flag)
			ans = min(ans, ant);
	}
	printf("%lld\n", ans);
	return 0;
}

B - Special Subsets

题意:寻找满足条件的集合个数。
题解:找环的个数\(cyc\),答案为\(2^{cyc}-1\)
代码如下:

#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int NMAX = 2e5 + 10;
const int MOD = 998244353;
int vis[NMAX], num, ant,nxt[NMAX];
void dfs(int x)
{
	if(vis[x])
	{
		if(vis[x] == ant)	num++;
		return;
	}
	vis[x] = ant;
	dfs(nxt[x]);
}
 
ll fast_pow(ll a, int n)
{
	ll ans = 1;
 
	while(n)
	{
		if(n & 1) ans = ans * a % MOD;
		a = a * a %MOD;
		n >>= 1;
	}
	return ans;
}
int main(int argc, char const *argv[])
{
	int n;
	scanf("%d", &n);
	for(int i  = 1;i <= n;i++)
		scanf("%d", nxt + i);
	num = 0;
	for(int i = 1;i <= n;i++)
	{
		ant++;
		if(!vis[i])
			dfs(i);
	}
	printf("%lld\n", (fast_pow(2ll, num) - 1 + MOD)%MOD );
	return 0;
}

C - Sequence Scores

题意:一共有\(N\)个位置,有\(1-M\)的数字可以填写到这\(N\)个位置上,形成一个序列\(A\),求所有序列\(A\)\(f(A)\)的和,其中\(f(A)\)表示从序列\(X=[0,...,0]\)到序列\(A\)操作个数,操作是选定一个区间\([l,r]\)\(v\)使得\(X_i\)\(\max(X_i, v)\)

题解

官方题解
对于固定序列\(A\),\(f(A)\)为图的联通分量个数,若$$i<j \iff A_i = A_j, \nexists i<k<j 使得 A_k<A_i$$则\(<i,j>\)是联通的。对于一个序列\(A\)最坏情况需要的操作步数是\(N\),所以所有的序列最坏操作步数总和是\(ans = N \cdot M^N\),固定\(<i,j>\),保证\(A_i = A_j\),区间\((i,j)\)的值都大于\(A_i\)的个数有\(ant = \sum\limits_{i=1}^{N}\sum\limits_{j=i+1}^{N}(\sum\limits_{x=1}^{M}(M-x)^{j-i-1})\cdot M^{N-(j-i+1)}\),这样操作会使\(<i,j>\)联通,使得\(i,j\)的操作数减少一,还有对于邻近位置相等的数时也会使得操作数减少一,对于临近位置相等的数的操作步数,我们可以设置\(0^0=1\),那么ant将包含该操作数。故答案应为\(ans - ant\)。其中\(j-i\)\(x\)可以确定,故时间复杂度为\(O(N \cdot M)\), 本文写的代码写了fast_pow(),可以预处理。
代码如下:

#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int NMAX = 5003;
const int MOD = 998244353;
 
ll m_pow[NMAX];
 
ll fast_pow(ll a, int n)
{
	ll ans = 1;
	while(n)
	{
		if(n & 1)	ans = ans * a % MOD;
		a = a * a % MOD;
		n >>= 1;	
	}
	return ans;
}
int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	m_pow[0] = 1;
	for(int i = 1;i < n;i++)
		m_pow[i] = m*m_pow[i-1] % MOD;
	ll ans = 0;
	for(int j_i = 1;j_i < n;j_i++)
	{
		ll ant = 0;
		for(int x = 1;x <= m;x++)
			ant = (ant + fast_pow(m-x, j_i-1))%MOD;
		ans = (ans + ant*m_pow[n-j_i-1]%MOD*(n-j_i)%MOD)%MOD;
	}
	ans = (1ll*n*fast_pow(m, n)%MOD - ans + MOD)%MOD; 
	printf("%lld\n", ans);
	return 0;
}
posted @ 2021-03-16 16:15  jadelemon  阅读(180)  评论(0编辑  收藏  举报