Educational Codeforces Round 138 D. Counting Arrays(数论/计数原理)
题意:
对于一个数组,可以删除当且仅当,删除后这个位置后面的数将向前平移。现在给定和,问有多少个长度不超过,元素不超过的数组,存在不止一种的清空方式。
考虑长度固定为时的答案。正难则反,可以求出总数量然后减去只有一种清空方式的数组个数。首先可以注意到第一个位置的数无论什么时候都是可以清空的,那么一种方式是每次都删掉第一个位置的数,这对于任何数组都是一种合法的方案,那么就需要保证,在任何时候,从第二个位置开始的数都不能被删除,即这个长度为的数组一开始要满足:
对于第个位置的数,(这是因为如果一直删第一个位置的数,要删次才能到,在这之前的位置是一直到2都有可能)
这也就是说,是到中所有质数乘积的倍数且不能大于。设质数乘积的倍数是,那么合法的取值就有个,设这个值是,用乘法原理就能得到长度为的只有一种清空方式的数列个数为,因此也就能求出长度为的只有一种清空方式的数列个数了,用总数去减即可。
需要注意的是,因为很大,所以特别需要注意取模以免进行乘法的时候就爆long long。
#include <bits/stdc++.h>
#define ll long long
#define int long long
#define N 1000005
#define mod 998244353
using namespace std;
bool prime[N];
ll fpow(ll a, ll b) {
ll ans = 1;
for(; b; b >>= 1) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
}
return ans;
}
void solve() {
int n, m;
cin >> n >> m;
for(int i = 2; i <= N - 5; i++) {
if(!prime[i]) {
for(int j = 2 * i; j <= N - 5; j += i) {
prime[j] = 1;
}
}
}
int mul = 1;
int res = 1;
int tans = 0;
for(int i = 1; i <= n; i++) {
if(!prime[i]) {
mul = mul * i;
}
if(mul > m) break;
res = (res * ((m / mul) % mod)) % mod;//(m / mul)后要先取模 防止爆ll
tans = (tans + res);
}
int tot = 0;
int tmp = 1;
for(int i = 1; i <= n; i++) {
tmp = tmp * (m % mod) % mod;//要先对m取模 防止爆ll
tot = (tot + tmp);
}
cout << (tot - tans + mod) % mod;
}
signed main() {
int T = 1;
// cin >> T;
while(T--) {
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2020-10-21 Codeforces Round #677 (Div. 3) A-E