Loading

Codeforces Round 1097 Div2 解题报告

因为我太菜了,只提供 Div2A ~ Div2D。

A

从后往前遍历,如果遇到 \(i + 1 > 0\) 就对 \(i\) 进行一次操作。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 7;
int n, a[N];
void solve(){
  cin >> n;
  for(int i = 1; i <= n; i ++){
    cin >> a[i];
  }
  for(int i = n - 1; i >= 1; i --){
    if(a[i + 1] > 0) a[i] += a[i + 1];
  }
  int ans = 0;
  for(int i = 1; i <= n; i ++){
    ans += (a[i] > 0);
  }
  cout << ans << "\n";
}
signed main(){
  int t; cin >> t;
  while(t --) solve();
  return 0;
}

B

做这题时下楼体检了,叫同学帮我写的。

考虑到先把 \(\max\) 摆上来一定不会更劣。也就是说先摆最大值,然后把整个数组的 \(MEX\) 从小到大凑出来。然后随便摆。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 7;
int n, a[N], ans[N];
map<int,int> mp;

void solve(){
  cin>>n;
  mp.clear();
  for(int i=1;i<=n;i++){
    cin>>a[i];
    mp[a[i]]++;
  } sort(a+1,a+n+1);
  
  ans[1]=a[n]; mp[a[n]]--;
  int z=1;
  for(auto num:mp){
    if(!num.second) continue;
    ans[++z]=num.first;
    mp[num.first]--;
  }
  for(auto num:mp){
    int cnt=num.second;
    while(cnt--) ans[++z]=num.first;
  }
  
  int res=0,mex=0;
  for(int i=1;i<=z;i++){
    if(ans[i]==mex) mex=(ans[i]+1!=ans[1]?ans[i]+1:ans[1]+1);
    res+=ans[1]+mex;
  }
  cout<<res<<"\n";
}

signed main(){
  int t; cin >> t;
  while(t --) solve();
  return 0;
}

C

用一下括号经典的转化(左括号变成 \(1\),右括号变成 \(-1\))。然后对于 \(a\) 序列,能选 \(-1\) 就选 \(-1\),然后增加一个反悔机制。然后检查 \(b\) 就行了。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 7;
int n, a[N], b[N];
void solve(){
  cin >> n;
  int sum = 0;
  for(int i = 1; i <= n; i ++){
    char c; cin >> c;
    a[i] = (c == '(' ? 1 : -1);
    sum += a[i];
  }
  for(int i = 1; i <= n; i ++){
    char c; cin >> c;
    b[i] = (c == '(' ? 1 : -1);
    sum += b[i];
  }
  if(sum) return cout << "NO\n", void();
  for(int i = n; i >= 1; i --){
    if(a[i] > b[i]) swap(a[i], b[i]);
  }
  int pre = 0, cnt = 0;
  vector<int> v;
  for(int i = 1; i <= n; i ++){
    pre += a[i];
    if(a[i] < b[i]) v.push_back(i);
    while(pre < 0){
      if(v.empty()) return cout << "NO\n", void();
      int pos = v.back();
      v.pop_back();
      swap(a[pos], b[pos]), pre += 2;
    }
  }
  sum = 0; pre = 0;
  for(int i = 1; i <= n; i ++){
    pre += a[i];
    if(pre < 0) return cout << "NO\n", void();
    sum += a[i];
  }
  if(sum) return cout << "NO\n", void();
  sum = 0, pre = 0;
  for(int i = 1; i <= n; i ++){
    pre += b[i];
    if(pre < 0) return cout << "NO\n", void();
  }
  cout << "YES\n";
}
signed main(){
  int t; cin >> t;
  while(t --) solve();
  return 0;
}

D

直接找每一对下标的贡献(在多少种情况中会有逆序对)。

逆序对的条件是 \(a_i \times b_x > a_j \times b_y\)\(i < j\))。然后变成 \(\frac{a_i}{a_j} > \frac{b_y}{b_x}\)。直接找一遍 \(b\) 所有的坐标对,把所有的比值记下来放到 vector 里,然后排个序。

然后对于每一对 \(i < j\) 的下标组合,在 vector 里二分找到最后一个满足 \(\frac{a_i}{a_j} > \frac{b_y}{b_x}\) 的就好了。注意不要真用 double,还是可以用 pair 代表分数的。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2007, Misaka = 998244353;
int n, a[N], b[N];
int frc[N], inv[N];
int qpow(int x, int y){
  int res = 1;
  for(int i = y; i; i >>= 1){
    if(i & 1) (res *= x) %= Misaka;
    (x *= x) %= Misaka;
  }
  return res;
}
void solve(){
  cin >> n;
  for(int i = 1; i <= n; i ++) cin >> a[i];
  for(int i = 1; i <= n; i ++) cin >> b[i];
  if(n == 1) return cout << "0\n", void();
  vector<pair<int, int>> v(1, {0, 0});
  for(int i = 1; i <= n; i ++){
    for(int j = 1; j <= n; j ++){
      if(i == j) continue;
      int g = __gcd(b[i], b[j]);
      v.push_back({b[j] / g, b[i] / g});
    }
  }
  sort(v.begin() + 1, v.end(), [](pair<int, int> a, pair<int, int> b){
    auto [ax, ay] = a; auto [bx, by] = b;
    return ax * by < bx * ay;
  });
  int ans = 0;
  for(int i = 1; i <= n; i ++){
    for(int j = i + 1; j <= n; j ++){
      int l = 0, r = v.size();
      while(l + 1 < r){
        int mid = (l + r) >> 1;
        auto [x, y] = v[mid];
        if(a[j] * x < a[i] * y) l = mid;
        else r = mid;
      }
      (ans += l * frc[n - 2]) %= Misaka;
    }
  }
  cout << ans * inv[n] % Misaka << "\n";
}
signed main(){
  ios::sync_with_stdio(0), cin.tie(0);
  frc[0] = inv[0] = 1;
  for(int i = 1; i <= 2000; i ++){
    frc[i] = frc[i - 1] * i % Misaka;
    inv[i] = qpow(frc[i], Misaka - 2);
  }
  int t; cin >> t;
  while(t --) solve();
  return 0;
}
posted @ 2026-05-06 20:03  Trent900  阅读(132)  评论(0)    收藏  举报