CCPC 网络赛题解 (D/I/J)
D
根据题目给出的构造方式,
设
第一个大 dp[i][l][l-1] = dp[i][r+1][r] = 1
处理。
rep(i, 1, n) rep(l, 1, m) // n,m分别为a,t长度
rep(r, l, m) { // t的[l,r]在s_i出现多少次
dp[i - 1][l][l - 1] = 1; // 将不合法区间设为1,便于计算
dp[i - 1][r + 1][r] = 1;
int64_t& res = dp[i][l][r] = dp[i - 1][l][r]; // 循环取不到“左半段为空”情况,这里补上
rep(k, l, r) {
res += dp[i - 1][l][k] * dp[i - 1][k + 1][r]; //略去取模操作
if (s[i] == t[k]) res += dp[i - 1][l][k - 1] * dp[i - 1][k + 1][r]; }}
cout << dp[n][1][m];
I
题解给了一个非常神奇的 dp。设
这个子集性质保证了转移方程的成立,比较巧妙。
// 略去输入、取模
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1);
int ans = 0;
for (int d = 1; d <= 500; d++) {
for (int i = 1; i <= m; i++) {
c[i] = 0;
for (int j = 1; j <= n; j++) {
if (b[i] - a[j] < d) break;
c[i] += 1;
}
}
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= m; i++) {
dp[i][0] = 1;
for (int j = 1; j <= c[i]; j++)
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] * (c[i] - j + 1);
}
for (int i = 1; i <= n; i++) g[d] = g[d] + dp[m][i];
ans += g[d];
}
printf("%d\n", ans);
J
J 题是一个比较板子的线性基,但是我当时并不会。线性基是用于处理异或问题的常用工具,考虑求一列数
// 图示二进制拆分为矩阵 // 变换为行阶梯型(线性基)
a[1] = 44 00101100 p[6] = 01101101
a[2] = 28 00011100 p[5] = 00101100
a[3] = 109 01101101 p[4] = 00011100
a[4] = 3 00000011 p[2] = 00000011
求线性基模版(贪心):
uint64_t p[52];
void insert(uint64_t x) {
for (int i = 51; ~i; i--) {
if (!(x >> i)) continue;
if (!p[i]) {
p[i] = x;
break;
}
x ^= p[i];
}
}
还可以用高斯消元求,直接就是行阶梯型,没有中间的空行。
线性基能做的事有:
- 求异或和最大值;
- 求异或和最小值——直接输出
; - 求异或和第
大值——把 改为行最简形,把 的置位全部加进去; - 求一个数在给定集合的子集异或和中的排名(判断是否能被异或和表出)。
对于此题,我们令
void insert(ull x) {
for (int i = 31; ~i; i--) {
if (!(x >> i)) continue;
if (!p[i]) { p[i] = x; break; }
x ^= p[i];
}
}
int main() {
int T;
cin >> T;
while (T--) {
fill(p, p + 32, 0);
int n; cin >> n;
ull A = 0, B = 0;
for (int i = 1; i <= n; i++) cin >> a[i], A ^= a[i];
for (int i = 1; i <= n; i++) cin >> b[i], B ^= b[i], insert(a[i] ^ b[i]);
bool ok = 0;
for (int i = 31; ~i; i--) {
int a = (A >> i) & 1, b = (B >> i) & 1;
if (a == 0 && b == 0) continue;
if (a == 1 && b == 1) { A ^= p[i], B ^= p[i]; continue; }
ok = 1;
if (a == 1) {
for (int j = i - 1; ~j; j--) A = min(A, A ^ p[j]); // 不改变,A为最大值
if (!p[i]) cout << A << endl;
else {
B ^= p[i];
for (int j = i - 1; ~j; j--) B = min(B, B ^ p[j]); // 改变,B为最大值
cout << min(A, B) << endl;
}
} else {
for (int j = i - 1; ~j; j--) B = min(B, B ^ p[j]); // 不改变,B为最大值
if (!p[i]) cout << B << endl;
else {
A ^= p[i];
for (int j = i - 1; ~j; j--) A = min(A, A ^ p[j]); // 改变,A为最大值
cout << min(A, B) << endl;
}
}
break;
}
if (!ok) cout << max(A, B) << endl;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!