《如 何 速 通 一 套 题》3
A election
定数:普及+,普及-,普及-,无,总计普及。
(思维,实现,算法,数据结构,总计)
双指针,每一次只会打死最左的和最右的,计算是死左边还是死右边即可。
\(O(N \log N) - O(1)\)。
code
#include <bits/stdc++.h>
using namespace std;
struct node {
int x, id;
}arr[1000010];
int n, xx[1000010];
int lrmid(int x, int y) {
int l = arr[x].x, r = arr[y].x, ans = 0;
for(; l <= r; ) {
int mid = (l + r) >> 1;
//cout << mid << ' ' << mid - arr[x].x << ' ' << arr[y].x - mid << '\n';
if((mid - arr[x].x) > (arr[y].x - mid)) {
ans = mid, r = mid - 1;
}else {
l = mid + 1;
}
}
return ans;
}
int main() {
freopen("election.in", "r", stdin);
freopen("election.out", "w", stdout);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> arr[i].x;
arr[i].id = i;
}
sort(arr + 1, arr + n + 1, [](node a, node b) {return a.x < b.x;});
for(int i = 1; i <= n; i++) {
xx[i] = arr[i].x;
}
int i = 1, j = n;
for(; i < j; ) {
int a = lrmid(i, j);
int tmp = lower_bound(xx + i, xx + j + 1, a) - xx;
//cout << i << ' ' << j << ' ' << arr[i].id << ' ' << arr[j].id << ' ' << a << ' ' << tmp << '\n';
if((tmp - i) >= j - tmp + 1) {
j--;
}else {
i++;
}
}
cout << arr[i].id << '\n';
return 0;
}
B chaos
定数:提高,普及+,无,无,总计提高。
死因:现象看到了,本质没看到。
如下:
1 2 3 4 5 [k = n - 1]
1 5 4 3 2 [k += 3]
1 3 4 5 2 [k += 2]
如此以往......
有一些操作不会进行。一样是正确的。
\(O(N) - O(N)\)。
code
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, k, pos[100010], arr[100010];
signed main() {
freopen("chaos.in", "r", stdin);
freopen("chaos.out", "w", stdout);
cin >> n >> k;
k -= n - 1;
pos[1] = 1;
for(int i = 2, l = 2, r = n, rv = 0; i <= n; i++) {
if(k >= n - i) {
k -= n - i;
rv ^= 1;
}
if(rv) {
pos[i] = r;
r--;
}else {
pos[i] = l;
l++;
}
}
for(int i = 1; i <= n; i++) {
arr[pos[i]] = i;
}
for(int i = 1; i <= n; i++) {
cout << arr[i] << ' ';
}
cout << '\n';
return 0;
}
C defend
定数:提高,普及+,普及+,无,总计提高。
死因:没有想到优化。
定义 \(dp_{x, lst}\) 为最后一个为 \(x\),上一个为 \(lst\) 时至多能搞到几个人。
发现很难转移,于是引入一个辅助数组 \(dash\):
\(dash_{x, k}\) 表示当前为 \(x\),当前与上一个的 \(\operatorname{and}\) 的第 \(k\) 为固定为 \(1\) 时至多能搞到几个人。
然后就可以用 \(dash\) 优化 \(dp\) 了。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n, arr[2020], ans, dp[2020][2020], cnt[2020][110]; // dash is counted from the third number... or not?
int main() {
freopen("defend.in", "r", stdin);
freopen("defend.out", "w", stdout);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> arr[i];
}
arr[0] = arr[n + 1] = INT_MAX;
//cout << DFS(0, 0) - 2 << '\n';
for(int i = 1; i <= n; i++) {
dp[i][0] = 1;
for(int j = 31; j >= 0; j--) {
cnt[i][j] = 1;
}
}
for(int i = 1; i <= n; i++) {
for(int j = 0; j < i; j++) {
if(!j) {
ans = max(ans, dp[i][j]);
for(int k = 31; k >= 0; k--) {
if((arr[j] >> k) & 1) {
cnt[i][k] = max(cnt[i][k], dp[i][j]); // Update dash
}
}
continue;
}
int x = (arr[i] & arr[j]);
if(x) {
dp[i][j] = 1;
for(int k = 31; k >= 0; k--) {
if((x >> k) & 1) {
dp[i][j] = max(dp[i][j], cnt[j][k] + 1); // If there can be a dash
}
}
for(int k = 31; k >= 0; k--) {
if((arr[j] >> k) & 1) {
cnt[i][k] = max(cnt[i][k], dp[i][j]); // Update dash
}
}
ans = max(ans, dp[i][j]);
}
//cout << dp[i][j] << ' ';
}
//cout << '\n';
}
cout << max(min(n, 2), ans) << '\n';
return 0;
}
D standin
定数:提高-,普及+,提高,无,总计提高-。
死因:没有输出 -1
。
一开始我想枚举宽带,后来发现不用,具体见下图:
可以看到,直接按照宽带大小,从小到大转移即可。
\(O(N2^M) - O(2^M)\)。
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct node {
int x, k, mask;
}arr[110];
int dp[1 << 20], n, m, b, c, t, ans = LLONG_MAX;
signed main() {
freopen("standin.in", "r", stdin);
freopen("standin.out", "w", stdout);
cin >> n >> m >> b;
for(int i = 1; i <= n; i++) {
for(cin >> arr[i].x >> arr[i].k >> c; c--; ) {
cin >> t;
arr[i].mask |= (1 << (t - 1));
}
}
sort(arr + 1, arr + n + 1, [](node a, node b) {return a.k < b.k;});
memset(dp, 0x3f, sizeof(dp));
dp[0] = 0;
for(int i = 1; i <= n; i++) {
for(int j = (1 << m) - 1; j >= 0; j--) {
dp[j | arr[i].mask] = min(dp[j | arr[i].mask], dp[j] + arr[i].x);
}
if(dp[(1 << m) - 1] != 0x3f3f3f3f3f3f3f3f) {
ans = min(ans, dp[(1 << m) - 1] + arr[i].k * b);
}
}
cout << (ans == LLONG_MAX? -1 : ans) << '\n';
return 0;
}