2.11 CW 模拟赛 赛时记录
看题
\(\rm{T1}\)
是一个代码长度不超过 \(\textrm{500 B}\) 的计数?
不是很理解
\(\rm{T2}\)
神秘括号串
\(\rm{T3}\)
构造, 没啥思路
\(\rm{T4}\)
不到啊
总的来说冲 \(\rm{T1}\) 正解, 其他的骗暴力, 拼点高档上去就行了
状态完全没有回来, 不知道该怎么办
\(\rm{T1}\)
给了 \(\textrm{35 min}\) 思考
思路
题意
- 给定一个长为 的排列 和一个最初为空的大根堆
- 进行 次操作
- 取出堆顶放入 末尾
- 取出 开头放入堆
求最终得到的 的种类数
先手动模拟找下性质
观察一组合法的 \(b\) 的性质
- 记 \(b_i\) 中的数在原串中的位置为 \(pos_i\) , 那么对于 \(pos\) 中的逆序对 \((b_i, b_j)\) , 有 \(b_i > b_j\)
- \(pos_i\) 可以看做几个公差为 \(1\) 的下降拼起来, 例如
321 54 876
但是要求满足第一条, 也就是说每一段 \(p_1p_2p_3\cdots\) , 需要满足 \(a_{p_1} > a_{p_2} > a_{p_3} > \cdots\)
所以我们继续面向数据
1 4 2 3
对应位置
1 2 | 3 4
我们可以添加一些分割线, 然后依次摆放
发现一组明显的反例 2 3 1
也就是说 \(3\) 可以放在下降串 2 1 中间
完全没时间了, 脑子丢掉打暴力
暴力代码
#include <bits/stdc++.h>
const int MOD = 8580287;
const int MAXN = 1020;
namespace calc {
int add(int a, int b) { return a + b > MOD ? a + b - MOD : a + b; }
int mul(int a, int b) { return (a * b * 1ll) % MOD; }
int sub(int a, int b) { return a - b < 0 ? a - b + MOD : a - b; }
void addon(int &a, int b) { a = add(a, b); }
void mulon(int &a, int b) { a = mul(a, b); }
} using namespace calc;
int n;
int a[MAXN];
class subtask5
{
private:
int dp[MAXN << 1][MAXN];
public:
void solve() {
memset(dp, 0, sizeof dp);
dp[0][0] = 1;
for (int i = 1; i <= 2 * n; i++) {
for (int j = 0; j <= n; j++) {
if (j != 0) addon(dp[i][j], dp[i - 1][j - 1]);
if (j != n) addon(dp[i][j], dp[i - 1][j + 1]);
}
}
printf("%d", dp[n * 2][0]);
}
} s5;
class subtask12
{
private:
int ans = 0;
int tmp[MAXN], b[MAXN];
std::priority_queue<int> heap;
public:
void solve() {
for (int i = 1; i <= n; i++) tmp[i] = i;
do {
for (int i = 1; i <= n; i++) b[i] = tmp[i];
while (!heap.empty()) heap.pop();
int ahs = 1, bhs = 1;
while (ahs <= n && bhs <= n) {
while ((ahs <= n && bhs <= n) && (heap.empty() || heap.top() != b[bhs])) heap.push(a[ahs++]);
while ((ahs <= n + 1 && bhs <= n + 1) && (!heap.empty() && heap.top() == b[bhs])) heap.pop(), bhs++;
}
if (bhs == n + 1) addon(ans, 1);
} while(std::next_permutation(tmp + 1, tmp + n + 1));
printf("%d", ans);
}
} s12;
int main()
{
scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
/*特殊性质*/
bool sub4 = true, sub5 = true;
for (int i = 1; i <= n; i++) {
if (a[i] != n - i + 1) sub4 = false;
if (a[i] != i) sub5 = false;
}
// sub5 = false;
if (sub4) { printf("1"); return 0; }
if (sub5) { s5.solve(); return 0; }
/*30pts 诈骗*/
s12.solve();
return 0;
}
寻思了一下 \(\rm{T2}\) 打不出来 , 把后面题读了方便补题之后直接来冲 \(\rm{T1}\)
\(\rm{T2}\)
趋势
先把后面暴力打了, 这场寄了
思路
首先我们考虑怎么计算一个括号串中, 有多少句刀语
一些想法
好像用类似括号树的结构, 然后合并树上点可以很快地做出来, 但是那大概是考完之后的事情了, 现在只能考虑纯暴力, 主要原因是不会建树
打半天一直错, 破防了直接删了赛后重构
\(\rm{T3}\)
纯纯的方便补题所以开, 今天不计入 \(\rm{rank}\) , 太神经了
思路
好吧这个是真的不会
\(\rm{T4}\)
思路
不难发现可以跑房子之间的距离, 然后转化成一个什么什么问题, 没学过连名字都记不到, 好像叫最小流什么什么的
不知道复杂度是多少, 但是房子之间肯定不能 \(\mathcal{O} (pnm)\) 去做, 要考虑优化
理论上每个点只和与他最近的点连边最优秀, 所以染一遍色就行了
然后跑什么什么算法, 没学过不可能优化
总结
贤者时刻
以后打比赛一定要严格按照策略, 今天可能本来能试着做一下后面的题, 因为死磕的原因去世了

浙公网安备 33010602011771号