A - Least Product
题意:
思路:若有奇数个负数,则不需要任何操作。若存在0,也不需要任何操作。其余情况将任意一个数改为0即可。
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n;
cin >> n;
int a[n + 5];
for(int i = 0 ; i < n ; i ++)
cin >>a[i];
int cnt = 0;
for(int i = 0 ; i < n ; i ++){
if(a[i] < 0){
cnt++;
}
if(a[i] == 0){
cout << 0 <<endl;
return;
}
}
if(cnt % 2 == 0){
cout << 1 << endl;
cout << 1 << " " << 0 << endl;
}
else{
cout << 0 <<endl;
}
}
int main()
{
int t = 1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
B - Erase First or Second Letter
题意:
思路:由于只能删除前两个数,因此可以考虑固定字符串开头,然后每次删除第二个数就会多形成一个空字符串。然后遍历每一个字符,这样做是的。可以发现:对于同一个开头字母而言,前面位置删除后所能形成的字符串必然涵盖了后面位置开头所形成的字符串,因此不需要遍历所有字符,只需要遍历所有字母即可。这样复杂度是 的。
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n;
string s;
cin >> n;
int inf = n + 1;
cin >> s;
vector<int>P(26 , inf);
for(int i = 1 ; i <= n ; i ++){
P[s[i - 1] - 'a'] = min(P[s[i - 1] - 'a'] , i);
}
int ans = 0;
for(int i = 0 ; i < 26 ; i ++){
ans += inf - P[i];
}
cout << ans <<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C - Watering an Array
题意:
思路:假设一开始数组全为0,要让的最少操作需要次,且有 ,,因此整个数组的价值最多为1。由此可以发现,对于全是0的数组而言,只需要前一天选择操作1,让 , 第二天选择操作2。这样就能得1分,且这么做一定是最优的。由于一开始不一定全是0,所以在第一次使用操作2了之后,每两天能够得一分。接下来只需要枚举什么时候第一次用操作2就行了。
假设第 天第一次使用操作2,那么总共的得分为 初始数组得分 + 。而什么情况下会使得总得分更高,即连续使用操作1之后,初始数组得分变的更高了。由于初始数组得分最高为,所以只需要遍历前天使用操作1即可。复杂度为
#include <bits/stdc++.h>
using namespace std;
const int inf = 100;
void solve()
{
int n , k , d;
cin >> n >> k >> d;
int arr[n + 5] , brr[k + 5];
for(int i = 1 ; i <= n ; i ++){
cin >> arr[i];
}
for(int i = 0 ; i < k ; i ++){
cin >> brr[i];
}
int ans = -inf;
int dd = 0;
for(int i = 0 ; i < min(d , 2 * n) ; i ++){
int num = 0;
for(int j = 1 ; j <= n ; j ++){
num += (arr[j] == j);
}
ans = max(ans , num + (d - 1 - i) / 2);
for(int j = 1 ; j <= brr[dd] ; j ++){
arr[j]++;
}
dd++;
dd %= k;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
D - Yet Another Inversions Problem
思路: 对于一个数内部,即到之间的逆序对而言,只需要对q数组求一次逆序对即可。
接下来考虑数与数之间的情况。对于而言,大小在之间的数而言,与这些数能够形成的逆序对为....总共有个。因此与这些数所能形成的逆序对数量为。而对于大小在的数而言,与这些数能够形成的逆序对为....总共有。因此因此与这些数所能形成的逆序对数量为,如此不断往上倍增求答案,直到上限为止。
而相反,大小在之间的数而言,也是同样的考虑方式,如此不断除以二直到下限为止。详细可以看注释
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define int long long
const LL mod = 998244353;
const int N = 5e5;
struct BIT{//Binary indexed Tree(树状数组)
int n;
vector<int> tr;
BIT(int n) : n(n) , tr(n + 1 , 0){
}
int lowbit(int x){
return x & -x;
}
void modify(int x , int modify_number){
for(int i = x ; i <= n ; i += lowbit(i)){
tr[i] += modify_number;
}
}
void modify(int l , int r , int modify_number){
modify(l , modify_number);
modify(r + 1 , -modify_number);
}
int query(int x){
int res = 0;
for(int i = x ; i ; i -= lowbit(i))
res += tr[i];
return res;
}
int query(int x , int y){
return query(y) - query(x);
}
};
int tmp[N];
LL merge_sort(int q[], int l, int r)
{
if (l >= r) return 0;
int mid = (l + r) >> 1; // 二分区间
LL res = merge_sort(q, l, mid) + merge_sort(q, mid + 1, r);
//归并
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r)
{
if (q[i] <= q[j]) tmp[k ++] = q[i ++]; // 前面的排序正常,注意`=` 说明不是逆序对
else
{
res += mid - i + 1;
tmp[k ++] = q[j ++];
}
}
// 扫尾工作
while (i <= mid) tmp[k ++] = q[i ++];
while (j <= r) tmp[k ++] = q[j ++];
for (int i = l, j = 0; i <= r; i ++ , j ++) q[i] = tmp[j];
return res;
}
void solve()
{
int n , k;
cin >> n >> k;
BIT num(4 * n + 5) , sum(k + 5);
int a[n] , b[k];
for(int i = 0 ; i < n ; i ++){
cin >> a[i];
num.modify(a[i] , 1);
}
for(int i = 0 ; i < k ; i ++){
cin >> b[i];
}
int ans = merge_sort(b , 0 , k - 1);//自己内部的贡献
ans *= n;//
ans %= mod;
for(int i = 0 ; i < n ; i ++){
int x = a[i];//x 与 后面所形成的的逆序对
int cnt = 1;
while(x < 2 * n ){
int t = x * 2;
int nn = num.query(x , t);//a[i] * 2 ^ cnt > 这些数
if(nn == 0){
x = t;
cnt++;
continue;
}
int end = max(1LL * 0 , k - cnt);
int ns = (1 + end) * end / 2;
// cout << x << " " << t << " " << nn << endl;
// cout << "cnt :" << cnt <<"ns :" << ns << endl;
ans += ns * nn;
ans %= mod;
x = t;
cnt++;
}
x = a[i];
cnt = 1;
while(1){
if(x == 1)
break;
int t = (x + 1) / 2;
int nn = num.query(t - 1 , x - 1);//这些数 * 2 ^ cnt > a[i]
/* cout << t - 1 << " " << x - 1 << " " << nn << endl;*/
if(nn == 0){
x = t;
cnt++;
continue;
}
int st = min(k , cnt );//
int cntt = k - st + 1;
int res = k - cntt;
int ns = k * res + (st + k) * cntt / 2;
/* cout << "cnt :" << cnt <<"ns :" << ns << endl;*/
ans += nn * ns;
ans %= mod;;
x = t;
cnt++;
}
num.modify(a[i] , -1);
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}