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
", 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
", (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,
exists 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 = sumlimits_{i=1}^{N}sumlimits_{j=i+1}^{N}(sumlimits_{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
", ans);
return 0;
}