当前位置: 首页 > news >正文

【CF】Day56——Codeforces Round 940 (Div. 2) and CodeCraft-23 BCD

B. A BIT of a Construction

题目:

思路:

简单思维题

首先我们肯定可以想到,答案的值不可能超过 k 的最高有效位,比如 1011,答案最多只能是 4 位,那我们考虑时候可以构造出一种方法使得刚好能填满呢?

我们考虑到,如果一个数他是 1111 这种形式,那么可以直接放这个数即可,但是如果是 1000呢?首先我们最优的情况肯定是将后面的 0 全变为 1,且这一定是最优的,因为如果我们可以通过舍弃最高位而获得后面的所有位,比如 1000 我们可以使用 0111 0001 两个构造出,此时答案是 3,可以看出这显然是最优的

那观察归纳发现,其实我们可以先获取 k 的最高有效位 w,然后构造 2^{w} - 1 和 k - (2^{k} - 1)这两个数,我们发现这显然是最优的,因为我们最坏情况下都能获得 w - 1的答案,而什么时候能获得 w 呢?显然就是全为 1 的情况了,而这种情况我们用上诉方法也能构造出来

因此只要 n >= 2,我们就能按照上诉方法先构造两个数,然后其余全是 0,否则我们直接输出 k 即可 

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"void solve()
{int n, k;cin >> n >> k;if (n == 1){cout << k << endl;return;}int x = 0;for (int i = 31; i >= 0; i--){if (k & (1ll << i)){x = i;break;}}cout << (1ll << x) - 1 << " " << k - (1ll << x) + 1 << " ";for (int i = 1; i <= n - 2; i++) {cout << "0 ";}cout << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}

C. How Does the Rook Move?

题目:

思路:

DP思维题

我们观察发现,一开始的选法其实不重要,重要的是选完后我们还剩下多少个 行/列 可以选择

比如行列是 3 的情况,我们发现我们可以选择删除删除左上角或者左下角的元素,这样只删除了一行/列,这样我们的问题就变为了变成 行列是2的情况,否则我们就会删除 2 行/列,这样就变成了 行/列是 1 的情况

我们发现这其实可以转化为子问题,因此我们可以用递推来写

我们定义 dp[i] 为行/列为 i 时的所有可能,初始化 dp[0] = dp[1] = 1,接下来我们推导转移方程,我们对于 i 行/列 的情况,我们可以只删去一 行/列 看看它能变成什么情况,如果我们放在对角线,那么就变成了 i-1 行/列 的情况,否则我们肯定会删去两 行/列,因为电脑也会下,所以就变成了 i-2 行/列 的情况,因此可以推出 dp[i] = dp[i-1] + dp[i - 2] * (n - 1),但是由于我们可以和电脑交换位置,所以最后应该是 dp[i] = dp[i-1] + dp[i - 2] * (n - 1) * 2

为什么是这样考虑呢?我们假设我们第一个删除的是第一行,那么我们可以放第一个点,即对角线上,或者放后面的点,即其余 (n - 1) 个位置上,我们发现无论我们选哪一行当作开始,我们都会再别的行当作开始的情况下存在(情况之间可以通过平移互换得到),即与我们选哪里当作开始点无关,因此就是 dp[i-1] 而不是 dp[i - 1] * n

最后按照转移方程初始化即可,每次查询获取剩余行数 t,然后直接输出 dp[t] 即可

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
const int MOD = 1e9 + 7;
int dp[300005];
void solve()
{int n, k;cin >> n >> k;int t = n;for (int i = 0; i < k; i++){int r, c;cin >> r >> c;if (r != c){t--;}t--;}cout << dp[t] % MOD << endl;
}signed main()
{dp[0] = dp[1] = 1;for (int i = 2; i <= 300000; i++){dp[i] = dp[i-1] + (2 * i - 2) * dp[i - 2];dp[i] %= MOD;}cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}

D. A BIT of an Inequality

题目:

思路:

好题,值得学习

看到题目给的这个式子,我们不难发现其实就是 f(x,z) ^ y > f(x,z),那么如果要让 f(x,z) 异或 y 后 值变大 那么一定是 y 的最高有效位 w 造成了奉献,即 f(x,z) 的第 w 位是 0

为什么一定是最高有效位造成了奉献呢?假如不是最高有效位,那么最高有效位一定会造成负奉献,此时即使后面所有位都造成正奉献也抵消不了最高位的奉献,因此只需要考虑最高位即可

那么就是 f(x,z) 的 w 位是 0 这种情况了,那我们如何求呢?

我要快速知道 f(x,z),对于这种区间问题我们显然可以使用前缀和来求,我们定义 s[i] 为前 i 位的异或和,那么 f(x,z) = s[z] ^ s[x - 1],因为根据异或性质可以知道 x ^ x = 0,所以我们异或掉前面的数就相当于删去,哪知道这个我们如何解决问题呢?

由于我们要保证 f(x,z) 的 w 位是 0,那么也就是说 s[z] 和 s[x - 1] 的 w 位都是 0/1,所以我们还需要一个前缀和 onehas[i][j] 来统计 前 i 个 s[i] 中第 j 位是 1 有多少个选择(位置),而 0 的位置我们只需要用当前位置减去 1 的数量即可

因此最后我们只需要这样写,我们枚举每个 a[i] 当作 y ,然后利用乘法原理来计算答案,具体的我们统计 i 位置前有多少个 s[i] 的 w 位是 0/1(以及 i 位置后),然后二者相乘即可,因为我们不需要知道具体的值,我们只需要知道我们选的两个端点 z x 的位置是不一样的即可,所以利用浅醉和计算符合条件的位置的数量是个很快的方法

具体实现看代码

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"void solve()
{auto getw = [](int x) ->int{for (int i = 30; i >= 0; i--){if (x >> i & 1)return i;}return 0;};int n;cin >> n;vector<int> a(n+1,0);//前缀和vector<int> s(n + 1, 0);//在前 j 个前缀和里有 onehas个数是 第 i 位是 1vector<vector<int>> onehas(31, vector<int>(n+1, 0));for (int i = 1; i <= n; i++){cin >> a[i];s[i] = s[i - 1] ^ a[i];for (int j = 30; j >= 0; j--){onehas[j][i] = onehas[j][i - 1] + (s[i] >> j & 1);}}int res = 0;for (int i = 1; i <= n; i++){//取得 a[i] 的最高位是多少int w = getw(a[i]);res += onehas[w][i - 1] * (onehas[w][n] - onehas[w][i - 1]);res += (i - onehas[w][i - 1]) * (n - i + 1 - (onehas[w][n] - onehas[w][i - 1]));}cout << res << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}

http://www.xdnf.cn/news/383491.html

相关文章:

  • 警备,TRO风向预警,In-N-Out Burgers维权风暴来袭
  • 25.K个一组翻转链表
  • 2025年PMP 学习七 -第5章 项目范围管理 (5.4,5.5,5.6 )
  • 多线程获取VI模块的YUV数据
  • 21、DeepSeekMath论文笔记(GRPO)
  • 十七、统一建模语言 UML
  • Win11安装APK方法详解
  • Trex -用 Python生成特定的流量模式
  • C++:this指针
  • CMake 入门实践
  • 牛客练习赛138
  • 8.5 表格进阶
  • (四)毛子整洁架构(Presentation层/Authentiacation)
  • 批量修改json文件中的标签
  • 【MCAL】TC397+EB-tresos之I2c配置实战(同步、异步)
  • 2025年客运从业资格证备考单选练习题
  • Wallcraft 3.53.0 | 提供高质量动态4D壁纸,解锁高级版,无广告干扰
  • 《Python星球日记》 第50天:深度学习概述与环境搭建
  • 数据治理框架在企业中的落地:从理念到实践
  • OSPF案例
  • 完整进行一次共线性分析
  • Java代理
  • Android开发-图像显示
  • 如何通过合法数据变现实现收入增长
  • LVGL对象的盒子模型和样式
  • Arduino 开源按键库大合集(单击/双击/长按实现)
  • VB与Excel无缝连接实现指南
  • 编译后的js文件如何跟进调试
  • OpenAI的商业化之路:从非营利到盈利的转型
  • IC ATE集成电路测试学习——开尔文连接