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
ightarrow 11
ightarrow 111
ightarrow 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 igoplus a_2 igoplus ··· igoplus a_i),(b[1] = a_1)。满足(b[1] < b[2] < ··· < b[n])
题解
(d) 和 (m) 都超级大,又涉及异或运算,考虑从二进制入手。满足(a)的递增比较简单,重点是怎么确保(b)的递增。有 (b[1] = a_1),(b[2] = a_1 igoplus 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("
");
}
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;
}