A - Lucky Direction:
题意:给你一个字符串 D 代表八个方向(北、东、西、南、东北、西北、东南、西南)之一。打印与 DD 表示的方向相反的字符串
思路:模拟
string s;
cin >> s;
for(auto op : s){
if(op == 'W')cout << 'E';
if(op == 'E')cout <<'W';
if(op == 'S')cout <<'N';
if(op == 'N')cout <<'S';
}
B - Seek Grid
题意:给你一个 N×N 网格 S 和一个 M×M 网格 T 。位于从上往下第 i 行和从左往上第 j 列的单元格用 (i,j) 表示,求一个点x , y,使得S中含x , y的右下方 m * m 个元素与T匹配
思路:M,N<50 。On^4模拟即可
int n , m;
cin >> n >> m;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
cin >> s[i][j];
}
}
for(int i = 1;i<=m;i++){
for(int j = 1;j<=m;j++){
cin >> t[i][j];
}
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
bool f = true;
for(int now_i = 0;now_i<m;now_i++){
for(int now_j = 0;now_j < m;now_j++){
if(s[i+now_i][j+now_j] != t[now_i+1][now_j+1]){
f = false;
}
}
}
if(f == true){
cout << i << " " << j << endl;
return 0;
}
}
}
C - Pigeonhole Query
题意:
有 N 只鸽子,编号从 1 到 N ,有 N 个鸽巢,编号从 1 到 N 。最初,鸽子 i 在 1≤i≤N 的巢 i 中。
您会收到 Q 个查询,您必须按顺序处理这些查询。查询有两种类型,每种都以下列格式之一给出:
1 P H: 将鸽子 P 移至鸽巢 H 。2: 输出包含一只以上鸽子的鸽巢数量。
思路:比较坑的一点是:把鸽子P移动到鸽巢H,不是把鸽巢P中的鸽子,所以要存储一下鸽子所在的巢穴pos,然后模拟即可
int n , q;
cin >> n >> q;
vector<int> pos(n+1);
map<int,int>mp;
for(int i = 1;i<=n;i++){
pos[i] = i;
mp[i] = 1;
}
int cnt = 0;
while(q--){
int t;cin >> t;
if(t == 1){
int p , h;
cin >> p >> h;
if(mp[pos[p]] == 2)cnt--;
if(mp[h] == 1)cnt++;
mp[pos[p]]--;
pos[p] = h;
mp[h]++;
}
else cout<< cnt << endl;
}
D - Gravity
题意:在平面直角坐标系中有一些方块,下落的方式与俄罗斯方块一致,每秒钟下落一格,输出Q个查询中,在t+0.5是是否存在区块a
思路:我们发现每个区块消去的时间仅收到以下两个因素影响
1:在不在最底下
2:能不能形成一列
很明显使用vector套小根堆即可,小根堆套一个PII来存储具体的下落时间和位置
struct HeapCmp{bool operator()(const PII &a,const PII &b)const {return a.fi > b.fi;}};
template <typename T> class Heap : public priority_queue<T, vector<T>, HeapCmp> {public:using priority_queue<T, vector<T>, HeapCmp>::priority_queue;};
// Code Start Here
int n , w;
cin >> n >> w;
vector<Heap<PII>> q(w+1);
vector<int> ans(n+1,INF);
for(int i = 1;i<=n;i++){
int x , y;
cin >> x >> y;
q[x].push(mkp(y,i));
}
bool f = true;
while(f){
int max_val = -INF;
for(int i = 1;i<=w;i++){
if(q[i].empty()){
f = false;
break;
}
max_val = max(max_val,q[i].top().fi);
}
if(!f)break;
else{
for(int i = 1;i<=w;i++){
ans[q[i].top().se] = max_val;
q[i].pop();
}
}
}
int t;
cin >> t;
while(t--){
int x , y;
cin >> x >> y;
if(x >= ans[y])cout <<"No\n";
else cout <<"Yes\n";
}
return 0;
E - Hierarchical Majority Vote
题意:
对于一个长度为 3^n 的 01 字符串 B=B_1,B_2,…,B_3n,定义一种操作获得长度为 3^n−1 的 01 字符串 C=C_1,C_2,…,C_3n−1:
对于 i=1,2,…,3n−1,令 C_i 为 B_3i、B_3i−1、B_3i−2 中出现次数最多的字符。
现给定一个长度为 3^N 的 01 字符串 A=A_1,A_2,…,A_3^N。设 A′=A_1′ 是通过 N 次上述操作后得到的长度为 1 的字符串。
请求出最少改变 A 中多少个元素(0 变 1,1 变 0),以改变 A_1′
思路:题意很绕,我们通过几组样例来看是怎么变换的
对于:010011101
第一层的三个子串 010 011 101
第一层三个子串出现最大值: 0 1 1,组成第二层子串 011
第二层子串 011 只有一个子串,出现最大值 1 A = 1
在此层修改一个1 为0即可改变A变为1
我们可以采取这样一种办法:对于每个节点,维护要修改的最小代价。
三个节点的值有以下三种情况:
1:三个结点中 0 的个数为 3,a1=0,将三个儿子中两个 0 都修改,于是 a2 的值即为三个儿子中前两小的和。
2:三个结点中 1 的个数为 3, a1=1,将三个儿子中两个 1 都修改,于是 a2 的值即为三个儿子中前两小的和。
3:三个结点中 0 的个数为 2,a1=0,将三个儿子中的其中一个 0 更改,于是 a2 的值为对应的信息 1 为 0 的较小者。
4:三个结点中 1 的个数为 2, a1=1,将三个儿子中的其中一个 1 更改,于是 a2 的值即为对应的信息 1 为 1 的较小者。
综上所述,对于每一层递归,首先将区间划分为三部分,对每部分分别进行递归处理。对于每一层的投票:统计三个子区间的结果,如果所有结果都是 0 或 1,则返回该值,并计算出所需的修改次数。如果是两种不同的结果,选择一个值并计算最小的修改次数。
显然这是一个dfs
int a[N], n, f[N]; // a 存储输入的二进制串,f 用来存储递归的结果
int t;
cin >> t;
n = pow(3, t);
for (int i=1;i<=n;i++) scanf("%1lld",a+i);
auto dfs = [&](auto dfs,int l, int r)->PII{
if (l == r) return {a[l], 1}; // 没有更改
PII x = dfs(dfs,l, l + (r - l + 1) / 3 - 1);
PII y = dfs(dfs,l + (r - l + 1) / 3, l + (r - l + 1) / 3 * 2 - 1);
PII z = dfs(dfs,l + (r - l + 1) / 3 * 2, r);
int cnt[2] = {0, 0};
cnt[x.first]++;
cnt[y.first]++;
cnt[z.first]++;
if (cnt[0] == 3) {
// 三个部分的投票结果都是 0
int b[] = {x.second, y.second, z.second};
sort(b, b + 3);
return {0, b[0] + b[1]}; // 返回最小的两个
}
else if (cnt[1] == 3) {
// 三个部分的投票结果都是 1
int b[] = {x.second, y.second, z.second};
sort(b, b + 3);
return {1, b[0] + b[1]}; // 返回最小的两个
}
else if (cnt[0] == 2) {
// 如果有两个部分的投票结果是 0,则返回投票结果为 0,并取修改次数最少的部分
int ans = 1e18;
if (x.first == 0) ans = min(ans, x.second); // 若当前部分的投票结果是 0,取其修改次数
if (y.first == 0) ans = min(ans, y.second);
if (z.first == 0) ans = min(ans, z.second);
return {0, ans};
}
else if (cnt[1] == 2) {
// 如果有两个部分的投票结果是 1,则返回投票结果为 1,并取修改次数最少的部分
int ans = 1e18;
if (x.first == 1) ans = min(ans, x.second);
if (y.first == 1) ans = min(ans, y.second);
if (z.first == 1) ans = min(ans, z.second);
return {1, ans};
}
};
cout <<dfs(dfs,1,n).second;
return 0;

1231

被折叠的 条评论
为什么被折叠?



