AtCoder Regular Contest 116 补题(C、D、E)

C - Multiple Sequences

题意:

给定数字NM,问有多少个长度为N的序列,满足1AiM,且Ai+1Ai的倍数

思路:

由于序列是成倍变大的,所以序列肯定是一个非严格单调递增的序列,那么可以枚举最后一个数An,通过递推可知,前面的数都是An的约数,所以就相当于将An的质因数拆解后,往前面n1个空放,对于每个因子来说都是独立的,所以质因数分解后,当前这个因子就是pici,当前因子为ci,由于因子是可不选的,所以相当于有n个空(1个是用来代表空放的),有c个球,所以放的方案数就是(n+c1n1),对于当前枚举的数,i=1n(n+ci1n1),然后把所有枚举的情况累加即答案

View Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e5 + 10;
const int mod = 998244353;
int fact[N], infact[N];
int n, m;
int lowbit(int x) { return x & -x; }
int qmi(int a, int k) {
int res = 1;
while (k) {
if (k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
void init() {
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i++) {
fact[i] = fact[i - 1] * i % mod;
}
infact[N - 1] = qmi(fact[N - 1], mod - 2) % mod;
for (int i = N - 2; i >= 1; i--) {
infact[i] = infact[i + 1] * (i + 1) % mod;
}
}
int C(int n, int m) {
if (m > n) return 0;
return fact[n] * infact[m] % mod * infact[n - m] % mod;
}
signed main() {
init();
cin >> n >> m;
int res = 0;
for (int i = 1; i <= m; i++) {
int now = i;
int temp = 1;
for (int j = 2; j <= now / j; j++) {
if (now % j == 0) {
int cnt = 0;
while (now % j == 0) {
now /= j;
cnt++;
}
temp = temp * C(n + cnt - 1, n - 1) % mod;
temp %= mod;
}
}
if (now > 1) temp = temp * C(n, n - 1) % mod;
temp %= mod;
res = (res + temp) % mod;
}
cout << res << endl;
}

D - I Wanna Win The Game

题意:

给定NM,现在问你有多少个序列满足下面的条件。Ai>=0i=1nAi=M,A1xorA2xorA3.....An=0

思路:

有异或操作,考虑将M分解成二进制01数来考虑,由于所有数的异或和为0,则说明对于M的每一位,都必须要有偶数个1,保证异或为0,那么对于每一位就可以考虑有多少个1,每一位有2,2×22×3....2×k个1,也就是说每一位的大小都可以是2×2i,4×2i....2×k×2i,这就相当于是分组背包,每个组可以挑选体积为2×k×2i的物品,此时定义f(i,j)定义为考虑M分解成二进制后的前i位,体积为j的方案数,那么最终答案就是f(log2M,M),转移方程为f(i,j)=f(i,j)+f(i1,j2×k×2i)×(n2k),相当于选出这些1后,分给n个空,方程可以优化前一维,最终输出f(M)就是答案

View Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5010;
const int mod = 998244353;
int fact[N], infact[N];
int n, m;
int f[N];
int qmi(int a, int k) {
int res = 1;
while (k) {
if (k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
void init() {
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i++) {
fact[i] = fact[i - 1] * i % mod;
}
infact[N - 1] = qmi(fact[N - 1], mod - 2) % mod;
for (int i = N - 2; i >= 1; i--) {
infact[i] = infact[i + 1] * (i + 1) % mod;
}
}
int C(int n, int m) {
if (m > n) return 0;
return fact[n] * infact[m] % mod * infact[n - m] % mod;
}
signed main() {
init();
cin >> n >> m;
f[0] = 1;
for (int i = 0; (1 << i) <= m; i++) {
for (int j = m; j >= 0; j--) {
for (int k = 1; 2 * k * (1 << i) <= j; k++) {
if (j >= 2 * k * (1 << i)) {
f[j] += f[j - 2 * k * (1 << i)] * C(n, 2 * k) % mod;
f[j] %= mod;
}
}
}
}
cout << f[m] << endl;
}

E - Spread of Information

题意:

给定N个点的的树,现在可以选K个点感染病毒,病毒以每秒一个点的速度向周边感染,问通过放置病毒,感染整棵树的最短时间为多少?

思路:

可以先把问题转换成给定时间X,来感染全图,最少需要多少病毒?可以发现时间是具有单调性的,所以是可以二分的,所以解决上面的问题,时间就可以用二分来枚举出来。给定时间来算感染全图需要的最少病毒数量,可以通过类树形dp搜索来解决
定义f(u)为在以u为子树的结点中,离它最近病毒的距离
g(u)在以u为子树的结点中,离它最远的未被感染的结点的距离
f(u)+g(u)<=x,说明以u为子树的所有结点都被感染了,所以当前点也会被感染,所以g(u)=inf
g(u)=x,距离当前点最远的未被感染的点的距离已经到了x,此时不放病毒的话,就会导致那个最远的点在限定时间内被感染,所以当前点必须被感染,f(u)=0,g(u)=inf,res++
最后回溯到根节点1,若g(1)0的话,说明病毒还没在时间内感染根结点,必须在根节点放置一个病毒

View Code
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
#define int long long
vector<int> e[N];
int n, k;
int f[N], g[N];
int res;
void dfs(int u, int fa, int limit) {
f[u] = inf, g[u] = 0;
for (auto v : e[u]) {
if (v == fa) continue;
dfs(v, u, limit);
f[u] = min(f[u], f[v] + 1);
g[u] = max(g[u], g[v] + 1);
}
if (f[u] + g[u] <= limit) {
g[u] = -inf;
} else if (g[u] == limit) {
f[u] = 0, g[u] = -inf;
res++;
}
}
bool check(int x) {
res = 0;
dfs(1, -1, x);
if (g[1] >= 0) res++;
return res <= k;
}
signed main() {
cin >> n >> k;
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
int l = 0, r = n;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
cout << l << endl;
}
posted @   Wraith_G  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
// //
点击右上角即可分享
微信分享提示