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 ;
}
posted @ 2024-01-27 14:56  ComistryMo  阅读(17)  评论(0)    收藏  举报