Educational Codeforces Round 138 (Rated for Div. 2) - D. Counting Arrays

数论 + 计数

Problem - D - Codeforces

题意

给定整数 n(1<=n<=3e5),m(1<=m<=1e12)

要求求长度为 n 的数组, 满足下列条件的个数

  1. 1<=a[i]<=m
  2. 对于每个位置 i, 当 gcd(a[i],i)=1 时可删去这个元素,直到删完所有元素;这个删除的过程是唯一的(即每次删除都有且只有一个位置可以删)(某个元素被删除后,他后面的元素会补上来,下标都 - 1)

思路

  1. 因为 gcd(a[1],1)=1 恒成立,所有每次删除都可以删第一个元素,要删除的过程是唯一的,则需要每次删除时只有第一个位置可以被删
  2. 对于第 i 个位置,因为每次都会删第一个元素,所以 y=a[i] 这个值会依次出现在 i,i1,i2...2,1 这些位置上,并且只有在 位置1 可以被删除,所以 a[i] 要与 1,2,3...,i 均不互质,即是 [1,i] 中的所有质数的倍数
  3. 维护 [1,i] 的质数积 tmp 即可,第 i 个位置可以取的数就是 mtmp; 注意 tmp>m 时就没必要再更新了,防止溢出
  4. 注意 m<=1e12, 在计算答案时 m 需要先取模再计算!!!

代码

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5 + 10;
const int mod = 998244353;
ll n, m;
int pr[N / 5], p[N], cnt;
ll f[N], s[N];
void get_primes(int n)
{
	p[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		if (!p[i])
		{
			p[i] = i;
			pr[++cnt] = i;
		}
		for (int j = 1; j <= cnt && pr[j] <= n / i; j++)
		{
			p[i * pr[j]] = pr[j];
			if (p[i] == pr[j])
				break;
		}
	}
}

ll qmi(ll a, ll b)
{
	ll ans = 1;
	while(b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	get_primes(N - 10);
	cin >> n >> m;
	ll sub = 0;
	ll tmp = 1;
	s[0] = 1;
	for (int i = 1; i <= n; i++)
	{
		if (p[i] == i && tmp <= m)
			tmp *= i;
		f[i] = m / tmp % mod;
		s[i] = s[i-1] * f[i] % mod;
		sub = (sub + s[i]) % mod;
	}
	ll ans = 0;
	for (int i = 1; i <= n; i++)
		ans = (ans + qmi(m % mod, i)) % mod;
	ans = (ans - sub + mod) % mod;
	cout << ans << endl;
    return 0;
}
posted @   hzy0227  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示