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;
}