Codeforces Round 917 (Div. 2)(A-D)
Codeforces Round 917 (Div. 2)(A-D)
A Least Product
分析
简单分类讨论 这里写的可能稍微有些麻烦
代码
点击查看代码
void solve () {
int n; cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++) cin >> a[i];
int cnn = 0, cnp = 0, cn0 = 0;
for (int i = 1; i <= n; i ++) {
if (a[i] < 0) cnn ++;
else if (a[i] == 0) cn0 ++;
else cnp ++;
}
if (cn0 != 0) {
cout << 0 << endl;
} else {
if (cnn == n) {
if (n & 1) {
cout << 0 << endl;
} else {
cout << 1 << endl;
cout << 1 << ' ' << 0 << endl;
}
} else if (cnp == n) {
cout << 1 << endl;
cout << 1 << ' ' << 0 << endl;
} else {
if (cnn & 1) {
cout << 0 << endl;
} else {
cout << 1 << endl;
cout << 1 << ' ' << 0 << endl;
}
}
}
return ;
}
B Erase First or Second Letter
分析
假设我们固定一个子串的开头在位置\(i\),那么我们可以得到\(n-i+1\)个不同的以\(s[i]\)开头的子串,O(n)遍历后可以求出不去重的所有答案
如何判重?我们考虑上述位置\(i\)的\(s[i]\)必须是首次出现的,因为若i位置的字符\(s[i]\)非首次出现,那么从\(s[i]\)首次出现的位置一定可以通过若干次操作二到达此\(i\)位置的状态
代码
点击查看代码
void solve () {
int n; string s; cin >> n >> s;
s = " " + s;
map<char, bool> mp;
ll ans = 0;
for (int i = 1; i <= n; i ++) {
if (mp[s[i]]) continue;
else {
mp[s[i]] = true;
ans += (n - i + 1);
}
}
cout << ans << endl;
return ;
}
C Watering an Array
分析
对于一个全0的序列而言,因为每次给一个前缀加1,那么整个序列肯定是单调不增的,在这样的序列中显而易见有且只有一个位置\(i\)使得\(i == a[i]\),因此最优操作就是加一次再清空一次,因为浪费再多次操作,清空时候的收益也只会是1。
那么问题转化为何时到达第一次全0,也就是第一次清空操作,我们需要尽可能使第一次清空的收益与其后的收益最大,也即\(sum = sum_1 + sum_2\),其中\(sum\)是总收益,\(sum_1\)是第一次清空的收益,\(sum_2\)是第二次清空的收益,我们不知道何时才能使\(sum\)最大,因此可以通过枚举第\(i\)天进行清空收获\(sum_1\),其后的时间全都收获\(sum_2\),那么我们该枚举到什么范围呢?显而易见的,根据第一段所说的道理,我们在\(sum_1\)上每花费两次操作,我们在\(sum_2\)上就会损失一点收益,而我们通过\(sum_1\)最多收获n点收益,因此枚举到\(2 * n\)即可。
代码
点击查看代码
void solve () {
ll n, k, d; cin >> n >> k >> d;
vector<ll> a(n + 1), b(k + 1);
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 0; i < k; i ++) cin >> b[i];
ll ans = 0;
for (int i = 1; i <= min(2 * n, d); i ++) {
ll cn = 0;
for (int j = 1; j <= n; j ++)
cn += (j == a[j]);
ans = max(ans, cn + (d - i) / 2);
for (int j = 1; j <= b[(i - 1) % k]; j ++)
a[j] += 1;
}
cout << ans << endl;
return ;
}
D Yet Another Inversions Problem
分析
代码
点击查看代码
const int N = 4e5 + 10;
int n, m;
ll tr[N];
int a[N], b[N], tmp[N];
ll merge_sort(int l, int r){
if (l >= r) return 0;
int mid = l + r >> 1;
ll res = merge_sort(l, mid) + merge_sort(mid + 1, r);
int k = 1, i = l, j = mid + 1;
while (i <= mid && j <= r)
{
if (b[i] <= b[j]) tmp[k ++] = b[i ++];
else{
tmp[k ++] = b[j ++];
res += mid - i + 1;
}
}
while(i <= mid) tmp[k ++] = b[i ++];
while(j <= r) tmp[k ++] = b[j ++];
for (int i = l, j = 1; i <= r; i ++, j ++) b[i] = tmp[j];
return res;
}
ll qmi(ll a, ll b) {
ll ans = 1 % mod;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll lowbit(ll x) {
return x & (-x);
}
ll query(int p) {
ll ans = 0;
while (p) {
ans += tr[p];
p -= lowbit(p);
}
return ans;
}
void add(int p, ll x) {
while (p <= N) {
tr[p] += x;
p += lowbit(p);
}
return ;
}
void solve () {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= m; i ++) cin >> b[i];
memset(tr, 0, sizeof tr);
ll ans = merge_sort(1, m) * n % mod;
for (int i = n; i >= 1; i --) {
ll nw = a[i];
ll cn = 0;
while (nw > 0 && cn < m) {
ll num = query(nw);
ans += num * (m - cn) % mod;
ans %= mod;
cn ++;
nw /= 2;
}
nw = a[i] * 2;
cn = 1;
while (cn < m) {
if (nw >= 2 * n + 1) {
ll s = (1 + (m - cn)) % mod * (m - cn) % mod * qmi(2, mod - 2) % mod;
ans += (n - i) * s % mod;
ans %= mod;
break;
}
ll num = query(nw);
ans += num * (m - cn) % mod;
ans %= mod;
cn ++;
nw *= 2;
}
add(a[i], 1);
}
cout << ans % mod << endl;
return ;
}

浙公网安备 33010602011771号