题目地址:https://codeforces.com/contest/1920
Problems A. Satisfying Constraints
思路
题目给出若干约束,求符合要求的数字个数。
若为1,则大于等于该约束;若为2,则小于等于该约束;若为3,则不能等于该约束。
对于前两种情况,统计最大左边界和最小右边界;对于第三种情况,存入数组中。然后统计在边界内的第三种情况的个数,最后用边界内数字个数减去区间内第三种情况的个数即可。
标程
void Solved() {
int n; cin >> n;
int mx = INF, mi = 0;
vector<int> a;
for(int i = 0; i < n; i ++ ) {
int x, y; cin >> x >> y;
if(x == 1) {
mi = max(mi, y);
} else if(x == 2) {
mx = min(mx, y);
} else {
a.push_back(y);
}
}
int sum = 0;
for(auto i : a) {
if(i >= mi && i <= mx) sum ++;
}
int res = mx - mi + 1 - sum;
cout << max(res, 0) << endl;
}
Problems B. Summation Game
思路
简单博弈,因为每人只操作一次,Bob希望结果数组之和最小,Bob会将前 x x x大的数都变为负,那么我们就只需要考虑Alice需要删除多少数字才能让结果数组之和最大。那么我们只需枚举 k k k次即可,对应Alice删除 0... k 0...k 0...k个数字,要使Bob取反后的数组之和最大,那么Alice删除数字将会按照从大到小的顺序。
标程
#define int long long
void Solved() {
int n, k, x; cin >> n >> k >> x;
vector<int> a(n + 1), b(n + 1);
int res = -INF;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
sort(a.begin() + 1, a.end());
for(int i = 1; i <= n; i ++ ) {
b[i] = a[i] + b[i - 1];
}
for(int i = n; i >= n - k; i -- ) {
int j = max(0ll, i - x);
res = max(res, b[j] - (b[i] - b[j]));
}
cout << res << endl;
}
Problems C. Partitioning the Array
思路
本题是一道同余数论。给定长度为 n n n的数组 a a a,然后将数组均分为若干份,如果当前分法可以找到每个子份对同一个数字取余后都相等,则分数加一,问能加多少分?
- 同余: 两个整数 a 、 b a、b a、b,如果他们同时除以一个自然数 m m m,所得的余数相同,则称 a 、 b a、b a、b对于模 m m m同余,记作 a ≡ b ( m o d . m ) a≡b(mod.m) a≡b(mod.m)
- 关于将数组均分为若干份,我们可以直接枚举即可。
- 而判断当前所有组是否可以对同一个数字取余后相等,需要遍历一遍数组。
标程
void Solved() {
int n; cin >> n;
vector<int> a(n);
for(auto &i : a) cin >> i;
int res = 0;
for(int i = 1; i <= n; i ++ ) {
if(n % i == 0) {
int g = 0;
for(int j = i; j < n; j ++ ) {
g = gcd(g, a[j] - a[j - i]);
}
res += (g != 1);
}
}
cout << res << endl;
}
Problems D. Array Repetition
思路
本题首先给出 n , q n,q n,q,然后给出 n n n次操作,每次操作有两种:1. 在数组后面添上一个数字 x x x,2. 将已有数组复制到数组后面 x x x次。然后有 q q q次查询,每次查询要求输出数组当前元素的值。
由于数组长度将会非常大,因此我们不能考虑模拟。文章来源:https://www.toymoban.com/news/detail-797266.html
- 我们可以记录每次操作过后的数组长度。
- 每次查询是直接查询数组下标,因此我们可以找到第一个令数组长度大于该下标的操作。
- 注意当数据比较大时会爆 l o n g l o n g long long longlong,因此在读入的时候要注意。
- 如果将所有数据(操作、当前数组长度)一起存,然后二分查找,这样会导致超时。
我们可以在读入的时候记录该次操作后的数组长度,然后记录该操作的 x x x,用来最后输出。每次查询的时候找到对应的操作,若是第二种操作,则将本次查询的下标对上一次操作的数组长度取模。最后必然找出的是第一次操作,输出即可。文章来源地址https://www.toymoban.com/news/detail-797266.html
标程
void solve(){
int n, q; cin >> n >> q;
ll dp[n + 1] = {};
int lstAdd[n + 1] = {};
vector<int> pos;
for (int i = 1, doAdd = true; i <= n; i++){
int a, v; cin >> a >> v;
if (a == 1) {
lstAdd[i] = v;
dp[i] = dp[i - 1] + 1;
} else {
lstAdd[i] = lstAdd[i - 1];
dp[i] = ((v + 1) > 2e18 / dp[i - 1]) ? (ll)2e18 : dp[i - 1] * (v + 1);
if (doAdd) pos.push_back(i);
}
if (dp[i] == 2e18) doAdd = false;
}
while (q--){
ll k; cin >> k;
for (int i = pos.size() - 1; i >= 0; i--){
int idx = pos[i];
if (dp[idx] > k && dp[idx - 1] < k){
if (k % dp[idx - 1] == 0){
k = dp[idx - 1]; break;
}
k %= dp[idx - 1];
}
}
cout << lstAdd[lower_bound(dp + 1, dp + n + 1, k) - dp]<<" \n"[q == 0];
}
}
超时代码(思路较直观)
#define int long long
struct arr{int x, y, z;};
arr a[N];
int n, q, sum;
int find(int m) {//找第一个大于m的a[i].z
int l = 1, r = n, mid;
while(l < r) {
mid = (l + r) / 2;
if(a[mid].z < m) l = mid + 1;
else r = mid;
}
return l;
}
void Solved() {
cin >> n >> q;
for(int i = 1; i <= n; i ++ ) {
cin >> a[i].x >> a[i].y;
if(a[i].x == 1) a[i].z = a[i - 1].z + 1;
else {
if((a[i].y > 2e18 / a[i - 1].z) && !sum){
a[i].z = 2e18;
sum = i;
} else {
a[i].z = a[i - 1].z * (a[i].y + 1);
}
}
}
while(q -- ) {
int m; cin >> m;
int t = find(m);
while(a[t].x == 2) {
m %= a[t - 1].z;
if(m == 0) m = a[t - 1].z;
t = find(m);
}
cout << a[t].y << " ";
}
cout << endl;
}
到了这里,关于Codeforces Round 919 (Div. 2)(A-D)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!