codeforce刷题
codeforce 1332D Walk on Matrix
题解
切入点是找出题目所给算法的错误之处,也就是每一次取最优解,但结果可能不是最优解的情况。比如:
111 100 0
11 111 11
按照给出的算法,\(dp[2][2] = 100_{(2)} = 4\),而\(dp[2][3] = 0_{(2)} = 0\),也就是在\(dp\)过程中,每次都取了最高位为1作为当前最优解。实际上,选择 \(111 \rightarrow 11 \rightarrow 111 \rightarrow 11\), 得到\(maxAnd = 11_{(2)} = 3\)。
构造出这样的样例后,将\(11_{(2)}\)换成\(k\)的二进制,写出矩阵就行啦
const int MAXN = 200005;
int get(int x, int op) {
int t = 0, tp = x;
while(tp) {
tp >>= 1;
t++;
}
if (op == 0) {
return (1 << t) + (~x & ((1 << t) - 1));
}
else {
return (1 << t) + x;
}
}
int main() {
int k; cin >> k;
int a[2][3] = {{get(k, 1), get(k, 0), 0}, {k, get(k, 1), k}};
cout << "2 3" << endl;
myfor(i, 0, 2) {
myfor(j, 0, 3) printf("%d ", a[i][j]);
cout << endl;
}
return 0;
}
整麻烦了,看这位大佬的构造:https://blog.csdn.net/weixin_42431507/article/details/105236247?>
CodeForces 1329B Dreamoon Likes Sequences
给两个数\(d(1 <= d <= 10^9)\)和\(m(1 <= m <= 10^9)\),问有多少种满足如下条件的\(a\)序列?方案数要模上\(m\)。
- \(a\)序列的长度为\(n\) \((1<= n <= d)\)
- \(1 <= a_1 < a_2 < ··· < a_n <= d\)
- 令\(b[i] = a_1 \bigoplus a_2 \bigoplus ··· \bigoplus a_i\),\(b[1] = a_1\)。满足\(b[1] < b[2] < ··· < b[n]\)
题解
\(d\) 和 \(m\) 都超级大,又涉及异或运算,考虑从二进制入手。满足\(a\)的递增比较简单,重点是怎么确保\(b\)的递增。有 \(b[1] = a_1\),\(b[2] = a_1 \bigoplus a_2\),\(a_2 > a_1\),那么\(b[2] > b[1]\)说明\(a_2\)的二进制长度大于\(a_1\)的二进制长度。以此递推,可以发现,\(a\)序列中元素的二进制长度是递增的,所以\(a\)的元素个数最多30个(\(2^{30} > 10^9\)).
将二进制长度相同的数划分为1组(比如4,5,6,7的二进制长度都是3,归为一组),然后每组只能取一个数,求方案数。举例来说:\(d = 5\),共有三组:\((1)\),\((2, 3)\),\((4, 5)\)。令\(ans_n :=\)表是长度为\(n\)且符合条件的\(a\)序列个数,根据组合数学的知识可得 \(ans_1 = 5\),\(ans_2 = 1 * 2 + 1 * 2 + 2 * 2 = 8\),\(ans_3 = 1 * 2 * 2 = 4\)。求得总的方案数: \(ans = ans_1 + ans_2 + ans_3 = 17\)。
最后,思考怎么\(code\)。硬搜肯定复杂度超了,令\(dp[i][j]:=\)前\(i\)个组选择\(j\)个数的方案数,有
注意爆
int啊
int bit_length(int x) {
int t = 0;
while(x) {t++, x >>= 1; }
return t;
}
void Inite() {
memset(cnt, 0, sizeof(cnt));
memset(dp, 0, sizeof(dp));
group = bit_length(d);
for (int i = 1; i < group; ++i) cnt[i] = 1 << (i - 1), d -= cnt[i];
cnt[group] = d;
//for (int i = 1; i <= group; ++i) printf("%d ", cnt[i]);
//printf("\n");
}
void Solve() {
cin >> d >> mod;
Inite();
for (int i = 1; i <= group; ++i) for (int j = 1; j <= i; ++j) {
if (j == 1) dp[i - 1][j - 1] = 1;
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * cnt[i] % mod) % mod;
}
long long ans = 0;
for (int i = 1; i <= group; ++i) ans = (ans + dp[group][i]) % mod;
cout << ans << endl;
}

浙公网安备 33010602011771号