2023.10.14 做题记录
2023.10.14 做题记录
P5595 歌唱比赛
一个非常简单的贪心。
先判断什么时候是 -1
,将字符串从头开始往后遍历,Z
的右边不能有 X,Y
,如果有则直接输出 -1
。
因为是 SPJ,如果该字符串有答案的话,倒着看,字母是谁的就随便给一个大的数,如果是 ,则小的数为 ,小的数为 ,其余情况同理。
CF1428B
若一个房间左边或右边是 -
,则其必符合条件,用 来统计。
若一个房间左右都是 <
,用 统计。
若一个房间左右都是 >
,用 统计。
当 >
和 <
都存在时, 和 类房间都不符合条件,答案为 。
当 <
存在且 >
不存在时, 类房间符合条件,答案为 。
当 >
存在且 <
不存在时, 类房间符合条件,答案为 。
CF743C
将 分为 +,
再根据裂项公式 -= 导出 =+
所以 =++
然后 ++=++
于是 )
CF476D
猜结论!
观察两组样例,可以发现共同点
- 样例一输出的是
1,2,3,5
- 样例二输出结果中最小的四个数是
2,4,6,10
不难发现,二者具有二倍关系,二者二倍关系刚好是
猜出结论!
cin >> n >> k;
cout << (6 * n - 1) * k << endl;
for (rint i = 1; i <= n; i++)
{
int x = 6 * i - 5;
cout << x * k << " " << (x + 1) * k << " " << (x + 2) * k << " " << (x + 4) * k << endl;
}
CF1430C
继续猜结论,一直从右往左删即可,最小值为
因为删到最后状态一定剩两个数,由于不可能剩两个 ,所以最小值为 。
我们可以将两个数相加除以二看作将两个数消成一个数,那要让剩下的数最小,就应该先去消大的,所以从右边开始消即可。
CF1025C
第一眼平衡树,第二眼区间 dp,第三眼大水题
先化环为链,然后求环上的最长交错字段,扫一遍就完事儿了,最后对串的长度除以二。
NOIP 2022 喵了个喵
首先观察数据范围,发现卡牌种类数 ,说明 与栈数量 之间有种神秘的关系。
先看 时的情形,发现 ,即每个栈分配两个不同的数,仍能留下一个空栈,把这个空栈记为 。
我们还注意到如果多于两个牌存在于一个栈中,中间的元素会比较尴尬,不好消掉,经常会造成无解情况。
于是有一种思路便呼之欲出了
每次从牌堆处理一张牌时,如果这张牌的图案在某个栈的顶部出现,那么对该栈进行操作 并消掉两张牌;
如果这张牌的图案在某个栈 的底部出现,那么对 栈进行操作 ,再对 和 进行操作 ,消掉两张牌;
否则对任意一个非 的栈进行操作 即可。
由于只有 种图案,这样的方法可以保证得出结果。可以骗到前 分
15 pts代码在后面。
再看 时的情形,这时上面的策略就不好用了,因为无法保证让 一直为空且让所有其他栈内不超过三张牌。
那么怎么解决呢?
任意时刻,设牌堆顶的牌为 。保留一个栈为空,记其为 。
策略 1:
条件:存在 ,且 的同类牌在场上存在 或 非 栈中存在至少一个栈大小不超过
- 除了 外,其他的栈都至多放 个元素。每次处理一张牌时,如果 在某个栈 的顶部出现过,那么把 放入 ;如果 在某个栈 的底部出现过,那么把 放入 ,对 和 进行操作 ;否则把 放入某个未满的非 栈里。
策略 2:
条件:存在 ,且 的同类牌在场上不存在 且 非 栈中没有栈大小不超过
- 记当前所有在栈顶的 个元素构成集合 。我们不断扫描之后的图案,直到遇到第一个不在 中的图案为止。
- 如果这个图案就是 :把牌堆顶的 和现在的 都放入 ,消掉它们。因为中间的所有元素都是栈顶,可以直接放入和它们对应的栈上。
- 如果这个图案不是 :那么这个图案 是某个栈 的栈底。记 的栈顶为 ,讨论 在刚刚扫描过的所有图案中出现次数的奇偶性:
- 奇数次:把 放入 ,所有的 放入 。这样 再次出现的时候, 上面的 被清空了,此时可以直接把 消掉, 变成新的 。
- 这个过程中,其他栈顶元素放入对应栈顶即可。
- 偶数次:把 放入 ,所有的 放入 (这里放到 里也行)。这样 再次出现的时候, 中自顶到底分别是 三个元素。把 放入 ,再消掉 和 的栈底,这样 中仍然只有两个元素。
- 这个过程中,其他栈顶元素放入对应栈顶即可。
关于操作限制,不用担心,因为无论哪种策略,最后都不可能操作超过 次。
代码如下:
#include <bits/stdc++.h> #define rint register int #define endl '\n' using namespace std; const int N = 2e6 + 5; const int M = 3e3 + 5; int T; int n, m, k; int a[N]; deque<int> stk[M];// 维护每个栈的栈底和栈顶的元素 int id[N]; // 维护所在栈的编号,若局面未出现则为 0 int num; // 辅助栈的编号 queue<int> q;// 用于维护哪些栈可以弹入元素。初始时除了辅助栈,每个栈可以弹入 2 次 vector<pair<int, int>> ans; // 保存答案 int read() { int x = 0; bool f = true; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = false; for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; return f ? x : (~(x - 1)); } void insert(int s, int x) // 操作 1,向 s 中插入 x { if (!stk[s].empty() && stk[s].back() == x) { stk[s].pop_back();// 若顶部两个元素相同则弹出 } else { stk[s].push_back(x);// 否则弹入 } ans.emplace_back(s, -1);// 添加入答案 } void del(int s1, int s2) // 操作 2,消除 s1 和 s2 的栈底 { stk[s1].pop_front();// 弹出栈底 stk[s2].pop_front();// 弹出栈底 ans.emplace_back(s1, s2);// 添加入答案 } bool simple(int x) // 新出来一个数 x,尝试简单相消 { int &s = id[x]; if (!s) // 若 x 未出现过 { if (q.empty()) // 没有可弹入的栈,return false { return false; } s = q.front(); q.pop(); insert(s, x); // 否则弹入下一个可弹入的栈 } else { q.push(s);// 若 x 出现过,一定能够消除,把原先 x 所在的位置弹入 q if (x == stk[s].back()) // 在栈顶 { insert(s, x); } else // 在栈底 { insert(num, x); del(num, s); } s = 0; // 然后改为局面未出现 } return true; } signed main() { cin >> T; while (T--) { cin >> n >> m >> k; for (rint i = 1; i <= m; i++) { a[i] = read(); } ans.clear(); memset(id, 0, sizeof id); num = n; while (!q.empty()) { q.pop(); } for (int i = 1; i < n; i++) { q.push(i); q.push(i); } for (rint i = 1; i <= m; i++) { if (!simple(a[i])) // 如果尝试简单相消行不通 { int u = a[i];// 记录当前数值 int r = i + 1; int v = a[r]; while (r <= m && v != u && stk[id[v]].back() == v) { v = a[++r]; // 寻找下一个不在栈顶的数 }// 此时,r 是 i 后第一个不在栈顶的下标,v 是 a[r] if (v == u) // 如果 v 正好和 u 一样 { insert(num, u); for (rint j = i + 1; j < r; j++) { simple(a[j]); } insert(num, v);// 把他们在辅助栈消除 } else // 否则 v 是某个栈 P 的栈底 { int p = id[v]; int w = stk[p].back();// 记 P 的栈顶为 w bool is_even = true;// 查看 w 出现次数奇偶性 for (rint j = i + 1; j < r; j++) { if (a[j] == w) { is_even = !is_even; } } if (is_even) // w 出现次数为偶数 { insert(p, u);// u 放入 P for (rint j = i + 1; j < r; j++) { if (a[j] == w) { insert(num, w); } else { simple(a[j]); } } insert(num, v); del(num, p);// 消除两个栈底的 v id[v] = 0; id[u] = p; } else { insert(num, u); for (rint j = i + 1; j < r; j++) { if (a[j] == w) { insert(p, w); } else { simple(a[j]); } } insert(p, v); id[v] = id[w] = 0; id[u] = num; q.push(num); num = p; } } i = r; } } printf("%d\n", (int)ans.size()); for (rint i = 0; i < (int)ans.size(); i++) { if (ans[i].second == -1) { printf("1 %d\n", ans[i].first); } else { printf("2 %d %d\n", ans[i].first, ans[i].second); } } } return 0; }
部分分
15pts
代码:#include <bits/stdc++.h> #define rint register int #define endl '\n' using namespace std; const int N = 1e6 + 5; int T; int n, m, k; int a[N]; deque<int> st[5000]; int id[N], spt; queue<int> q; vector<pair<int, int> > ans; void insert(int s, int x) { if(!st[s].empty() && st[s].back() == x) { st[s].pop_back(); } else { st[s].push_back(x); } ans.emplace_back(s, -1); } void del(int s1, int s2) { st[s1].pop_front(); st[s2].pop_front(); ans.emplace_back(s1, s2); } void simple(int x) { int &s = id[x]; if(!s) { if(q.empty()) { puts("-1"); exit(0); } s = q.front(); q.pop(); insert(s, x); } else { q.push(s); if(x == st[s].back()) { insert(s, x); } else { insert(spt, x); del(spt, s); } s = 0; } } signed main() { cin >> T; while(T--) { cin >> n >> m >> k; for(rint i = 1; i <= m; i++) { cin >> a[i]; } ans.clear(); memset(id, 0, sizeof(id)); spt = n; while(!q.empty()) { q.pop(); } for(rint i = 1; i < n; i++) { q.push(i); q.push(i); } for(rint i = 1; i <= m; i++) { simple(a[i]); } cout << ans.size() << endl; for(rint i = 0; i < ans.size(); i++) { if(ans[i].second == -1) { printf("1 %d\n", ans[i].first); } else { printf("2 %d %d\n", ans[i].first, ans[i].second); } } } return 0; }
- 奇数次:把 放入 ,所有的 放入 。这样 再次出现的时候, 上面的 被清空了,此时可以直接把 消掉, 变成新的 。
本文作者:PassName
本文链接:https://www.cnblogs.com/spaceswalker/p/17764430.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步