《如 何 速 通 一 套 题》6.0

邮寄

开场秒掉 A。

然后陷入了无尽的 BCD 循环中......

C 推了我好久,然后没推出来......

A 集合

考虑每一个子集和的贡献。设 dpi 表示子集和为 i 的方案数,转移易推。

答案是

i=1n(n+1)2idpi

但是 n200 会原地起飞,没事,我们可以取模......

注意!!

对于指数上的数,千万不要 mod998244353,要 mod998244352

根据费马小定理,ap11(modp)

然后就可以了......

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int kMod = 998244353;
int n, dp[40040], lm, ans = 1;
int qpow(int x, int y) {
int rs = 1;
for(; y; y >>= 1) {
if(y & 1) {
rs = rs * x % kMod;
}
x = x * x % kMod;
}
return rs;
}
signed main() {
freopen("set.in", "r", stdin);
freopen("set.out", "w", stdout);
cin >> n;
lm = n * (n + 1) / 2;
dp[0] = 1;
for(int i = 1; i <= n; i++) {
for(int j = lm - i; j >= 0; j--) {
dp[j + i] = (dp[j + i] + dp[j]) % (kMod - 1); // -1 is key
}
}
for(int i = 1; i <= lm; i++) {
ans = ans * qpow(i, dp[i]) % kMod;
}
cout << ans << '\n';
return 0;
}

B 出租

考虑一个区间 [l,r] 里面的人。

可以写出如下方程:

i=lrvalik(rl+1+d)

稍微变形一下:

i=lrvalik(rl+1+d)

i=lrvalik(rl+1)+kd

i=lr(valik)kd

维护左边的最大子段和,然后就可以直接判断了。

如何动态求解最大子段和(Spoiler Alert!)

动态维护,果断祭出线段树。

维护如下四个信息:

pm,sm,as,fs 代表(非空)前缀最大值,后缀最大值,最大子段和,区间和,

合并如下:

pm=max(pmls,fsls+pmrs)

sm=max(smrs,fsrs+smls)

as=max(asls,asrs,smls+pmrs)

fs=fsls+fsrs

由于只有单点修改,所以不需要多少维护。

#include <bits/stdc++.h>
#define int long long
using namespace std;
struct dat {
int pm, sm, as, fs;
dat(int s = -1e10, int p = -1e10, int d = -1e10, int f = -1e10) : pm(), sm(), as(), fs() {
pm = s, sm = p, as = d, fs = f;
}
dat operator ^(const dat &b) const {
return dat(max(pm, fs + b.pm), max(sm + b.fs, b.sm), max({as, b.as, sm + b.pm}), fs + b.fs);
}
}d[2000020];
int n, m, k, l, arr[500050], x, y;
void build(int id = 1, int l = 1, int r = n) {
if(l == r) {
d[id] = {arr[l], arr[l], arr[l], arr[l]};
return ;
}
int mid = (l + r) >> 1;
build(id * 2, l, mid);
build(id * 2 + 1, mid + 1, r);
d[id] = d[id * 2] ^ d[id * 2 + 1];
}
void modify(int x, int v, int id = 1, int l = 1, int r = n) {
if(l == r) {
arr[l] = v;
d[id] = {arr[l], arr[l], arr[l], arr[l]};
return ;
}
int mid = (l + r) >> 1;
if(x <= mid) {
modify(x, v, id * 2, l, mid);
}else {
modify(x, v, id * 2 + 1, mid + 1, r);
}
d[id] = d[id * 2] ^ d[id * 2 + 1];
}
dat query(int ql, int qr, int id = 1, int l = 1, int r = n) {
if(r < ql || qr < l) {
return dat();
}
if(ql <= l && r <= qr) {
return d[id];
}
int mid = (l + r) >> 1;
dat a = query(ql, qr, id * 2, l, mid), b = query(ql, qr, id * 2 + 1, mid + 1, r);
return a ^ b;
}
signed main() {
freopen("hire.in", "r", stdin);
freopen("hire.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> k >> l;
for(int i = 1; i <= n; i++) {
arr[i] -= k;
}
build();
for(; m--; ) {
cin >> x >> y;
modify(x, arr[x] + y);
dat tmp = query(1, n);
cout << (tmp.as > k * l? "NO" : "YES") << '\n';
}
return 0;
}

C 连通块

观察到我们只需要处理那些“不共戴天”的节点就可以了。

然后就自然可以 dp 了。

#include <bits/stdc++.h>
#define int ll
using namespace std;
using ll = long long;
struct node {
int u, v;
}cnd[22];
int n, m, val[100010], l, bg[44][44], tot, id[100010], dp[100010][44], ans;
vector<int> ch[100010];
void DFS(int x = 1) {
for(int i = 0; i <= tot; i++) {
dp[x][i] = -1e16;
}
dp[x][id[x]] = val[x];
for(auto i : ch[x]) {
DFS(i);
int mx = -1e16;
for(int j = 0; j <= tot; j++) {
if(!bg[j][id[i]]) {
mx = max(mx, dp[x][j]);
}
}
for(int j = 0; j <= tot; j++) {
dp[x][j] = max(dp[x][j], dp[i][j] + mx);
}
}
for(int j = 0; j <= tot; j++) {
ans = max(ans, dp[x][j]);
}
}
signed main() {
freopen("block.in", "r", stdin);
freopen("block.out", "w", stdout);
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> val[i];
}
for(int i = 1; i <= n; i++) {
cin >> l;
ch[i].resize(l);
for(auto &j : ch[i]) {
cin >> j;
}
}
ans = -1e16;
/*
for(int i = 1; i <= n; i++) {
ans = max(ans, val[i]);
}
if(ans <= 0) {
cout << ans << '\n';
return 0;
}
//*/
for(int i = 1; i <= m; i++) {
cin >> cnd[i].u >> cnd[i].v;
if(!id[cnd[i].u]) {
id[cnd[i].u] = ++tot;
}
if(!id[cnd[i].v]) {
id[cnd[i].v] = ++tot;
}
bg[id[cnd[i].u]][id[cnd[i].v]] = bg[id[cnd[i].v]][id[cnd[i].u]] = 1;
}
DFS();
cout << ans << '\n';
return 0;
}

D 跳棋

我们发现把所有的单个 1 拿出来后(奇数段中的一个 1 也算单个一,但是一个段中只有一个),剩下的 110 可以随便安排。

所以设 dpi,j,k,0/1 表示考虑了前 i 个,有 j11,有 k0,末尾是否可以加一个 1 变成 11

0 时:dpi,j,k,0/1dpi+1,j,k+1,0

1 时:dpi,j,k,0dpi+1,j,k,1,dpi,j,k,1dpi+1,j+1,k,0

然后答案是

i=1nj=1n(dpn,i,j,0+dpn,i,j,1)(i+jj)

#include <bits/stdc++.h>
#define int ll
using namespace std;
using ll = long long;
const int kMod = int(1e9) + 7;
int n, fac[1010], inv[1010], ans, dp[2][550][550][2];
string s;
void init() {
fac[0] = fac[1] = 1, inv[1] = 1;
inv[0] = 1;
for(int i = 2; i <= 1000; i++) {
fac[i] = fac[i - 1] * i % kMod;
inv[i] = inv[kMod % i] * (kMod - kMod / i) % kMod;
}
for(int i = 2; i <= 1000; i++) {
inv[i] = inv[i] * inv[i - 1] % kMod;
}
}
int c(int x, int y) {
if(x < 0 || y < 0 || x < y) {
return 0;
}
return fac[x] * inv[x - y] % kMod * inv[y] % kMod;
}
signed main() {
freopen("checkers.in", "r", stdin);
freopen("checkers.out", "w", stdout);
cin >> n >> s;
n = s.size();
dp[0][0][0][0] = 1;
for(int i = 0; i < n; i++) {
for(int j = 0; j <= n; j++) {
for(int k = 0; k <= n; k++) {
if(s[i] != '1') {
dp[1][j][k + 1][0] = (dp[1][j][k + 1][0] + dp[0][j][k][0] + dp[0][j][k][1]) % kMod;
}
if(s[i] != '0') {
dp[1][j][k][1] = (dp[1][j][k][1] + dp[0][j][k][0]) % kMod;
dp[1][j + 1][k][0] = (dp[1][j + 1][k][0] + dp[0][j][k][1]) % kMod;
}
}
}
for(int j = 0; j <= n; j++) {
for(int k = 0; k <= n; k++) {
dp[0][j][k][0] = dp[1][j][k][0], dp[0][j][k][1] = dp[1][j][k][1];
dp[1][j][k][0] = dp[1][j][k][1] = 0;
}
}
}
init();
for(int i = 0; i <= n; i++) {
for(int j = 0; j <= n; j++) {
ans = (ans + (dp[0][i][j][0] + dp[0][i][j][1]) % kMod * c(i + j, j)) % kMod;
}
}
cout << ans << '\n';
return 0;
}
posted @   hhc0001  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示