发现没几个人写这场比赛的题解,顺便给补题的人提供一点思路,故而火速出了这篇(不会都去打区域赛了吧,悲~)
A
点击查看代码
void solve() {
int n;
cin >> n;
cout << n - 1 << '\n';
}
B
模拟题
根据题意:
一、预约:
考虑为0的情况:1.此时读者有书 2.读者上次预约时间未超过d天
其余情况为1
二、借书
首先考虑预约情况,如果当天有预约先解决预约的读者,因此我们需要borp[t]数组表示第t天预约状况
考虑不能借到情况:1.箱子里没有书 2.已经有了一本书
否则输出书堆顶部的书
三、还书
记得清除
四、查看
res:预约
borp:预约借书
bor:借书
ret:还书
que:查询
细节注意:顺序不可搞错
点击查看代码
struct node {
int book, res, d;
};
struct node1 {
int id, d, idx;
};
void solve() {
int n, m;
cin >> n >> m;
vector<int> stack(n + 1);
iota(stack.begin(), stack.end(), 0ll);
vector<node> a(N);
vector<vector<node1>> res(N), bor(N), ret(N), que(N), borp(N);
for (int i = 1; i <= m; i ++) {
int t, id, d;
string s;
cin >> t >> s >> id;
if (s == "RESERVE") {
cin >> d;
res[t].push_back({id, d, i});
}
if (s == "BORROW") bor[t].push_back({id, 0, i});
if (s == "RETURN") ret[t].push_back({id, 0, i});
if (s == "QUERY") que[t].push_back({id, 0, i});
}
vector<int> ans(m + 1);
for (int i = 1; i <= 1000; i ++) {
for (auto [id, d, idx] : res[i]) {
if(a[id].book || a[id].res && i - a[id].res < a[id].d) {
ans[idx] = 0;
}
else {
ans[idx] = 1;
borp[i + d].push_back({id, d, 0});
a[id].res = i, a[id].d = d;
}
}
for (auto [id, d, idx] : borp[i]) {
if(stack.size() == 1||a[id].book || i - a[id].res < a[id].d) {
}
else {
a[id].book = stack.back();
stack.pop_back();
}
a[id].res = a[id].d = 0;
}
for (auto [id, d, idx] : bor[i]) {
if(stack.size() == 1||a[id].book || i - a[id].res < a[id].d) {
ans[idx] = 0;
}
else {
ans[idx] = stack.back();
a[id].res = a[id].d = 0;
a[id].book = stack.back();
stack.pop_back();
}
}
for (auto [id, d, idx] : ret[i]) {
if(!a[id].book) {
ans[idx] = 0;
}
else {
ans[idx] = a[id].book;
stack.push_back(a[id].book);
a[id].book = 0;
}
}
for (auto [id, d, idx] : que[i]) {
if(!a[id].book) ans[idx] = 0;
else ans[idx] = a[id].book;
}
}
for (int i = 1; i <= m; i ++) {
cout << ans[i] << '\n';
}
}
C
很明显0与任何数与都是0,且又要求之多操作n次,故而可以找到操作一次变成0,然后用0与其他数字与,观测数据范围,可以暴力求解
点击查看代码
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i ++) cin >> a[i];
for (int i = 0; i < n; i ++) {
for (int j = i + 1; j < n; j ++) {
if((a[i] & a[j]) == 0) {
cout << "Yes\n";
return;
}
}
}
cout << "No\n";
}
D
选择一个下标,然后让它的值减少1,最多操作k次,问最多的低谷是多少
尝试贪心,发现很复杂,看数据范围考虑dp
设dp[i][j]代表前i项,最多低谷为j
考虑如何转移,i不是低谷可继承前面,i为低谷,其值要小于两边的值,故而:
dp[i][j] = min(dp[i - 1][j], dp[i - 2][j - 1] + max(0, a[i] - min(a[i - 1], a[i + 1]) + 1))
点击查看代码
void solve() {
int n, k;
cin >> n >> k;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++) cin >> a[i];
vector<vector<int>> dp(n + 1, vector<int>(n + 1, 1e18));
dp[0][0] = dp[1][0] = 0;
for (int i = 2; i <= n - 1; i ++) {
for (int j = 0; j <= i; j ++) {
dp[i][j] = min(dp[i - 1][j], dp[i - 2][max(0ll, j - 1)] + max(0ll, a[i] - min(a[i - 1], a[i + 1]) + 1));
}
}
int ans = 0;
for (int i = n; i >= 0; i --) {
if(dp[n - 1][i] <= k) {
ans = i;
break;
}
}
cout << ans << '\n';
}
E
先观察数据,n很小考虑暴力
每天可以选一个技能释放,一共四个技能,一共4^n次,好像不太行
但是又有冷却时间的限制,故而当天最多可供选择的技能只有两个,总复杂度大约在2^n次,复杂度绰绰有余
然后就暴力枚举就行,看了别人提交的代码,发现自己写的有点复杂,就不解释了,可以看看别人提交的代码
点击查看代码
struct node {
int day, sum, d1, d2, d3, d4, ans;
};
void solve() {
int n, a;
cin >> n >> a;
vector<int> d(n);
for (int i = 0; i < n ; i ++) cin >> d[i];
int ans = 0;
queue<node> q;
q.push({0, 0, 0, 0, 0, 0, 0});
while(q.size()) {
auto [day, sum, d1, d2, d3, d4, Ans] = q.front();
q.pop();
if(day == n) {
ans = max(ans, Ans);
continue;
}
int Zero = (d1 == 0) + (d2 == 0) + (d3 == 0) + (d4 == 0);
int One = (d1 == 1) + (d2 == 1) + (d3 == 1) + (d4 == 1);
if(!Zero) continue;
if(One > 1) continue;
if(d1 == 0) q.push({day + 1, sum, 1, d2 ? (d2 + 1) % 3 : 0, d3 ? (d3 + 1) % 3 : 0, d4 ? (d4 + 1) % 3 : 0, Ans + d[day] * (d4 == 1 ? 2 : 1)});
if(d2 == 0) q.push({day + 1, sum + a, d1 ? (d1 + 1) % 3 : 0, 1, d3 ? (d3 + 1) % 3 : 0, d4 ? (d4 + 1) % 3 : 0, Ans});
if(d3 == 0) q.push({day + 1, sum, d1 ? (d1 + 1) % 3 : 0, d2 ? (d2 + 1) % 3 : 0, 1, d4 ? (d4 + 1) % 3 : 0, Ans + sum * (d4 == 1 ? 2 : 1)});
if(d4 == 0) q.push({day + 1, sum, d1 ? (d1 + 1) % 3 : 0, d2 ? (d2 + 1) % 3 : 0, d3 ? (d3 + 1) % 3 : 0, 1, Ans});
}
cout << ans << '\n';
}