Codeforces Round 915 (Div. 2)(A-E)

Codeforces Round 915 (Div. 2)(A-E)

A Constructive Problems

分析

一个简单的构造,结论就是max(n, m),不太想得明白的手画一下就行

点击查看代码
void solve () {
    int a, b; cin >> a >> b;
    cout << max(a, b) << endl;
    return ;
}

B Begginer's Zelda

分析

每次操作的本质就是合并两个叶子节点,到最后一步时根节点也变为叶子节点,所以最后答案为(叶子节点+1)/2

点击查看代码
const int N = 2e5 + 10;
vector<int> g[N];
int d[N];

void solve () {
    int n; cin >> n;
    memset(d, 0, sizeof d);
    for (int i = 1; i <= n - 1; i ++) {
    	int u, v; cin >> u >> v;
    	d[u] ++;
    	d[v] ++;
    }
    int cn = 0;
    for (int i = 1; i <= n; i ++) {
    	if (d[i] == 1) cn ++;
    }
    //cout << cn << endl;
    cout << (cn + 1) / 2 << endl;
    return ;
}

C Largest Subsequence

分析

因为第一次一定是取出最大的子序列,而后发现每一次操作的序列都是第一次子序列的子集,可以得出最终的操作数就是将第一次取出的子序列变为有序的操作数。如果将第一次取出的子序列排序后原序列仍不满足,则输出-1.

点击查看代码
const int N = 2e5 + 10;

int n;
string s;

void solve () {
    cin >> n >> s;
    s = " " + s;
    vector<int> a(n + 1), res(n + 1);
    vector<bool> used(n + 1, 0);
    vector<int> pos[26];
    vector<int> v;
    for (int i = 1; i <= n; i ++) {
    	a[i] = s[i] - 'a';
    	pos[a[i]].push_back(i);
    }
    int nw = 0;
    for (int i = 25; i >= 0; i --) {
    	for (auto nxtp : pos[i]) {
    		if (nxtp > nw) {
    			used[nxtp] = true;
    			v.push_back(nxtp);
    			nw = nxtp;
    		}
    	}
    }
    int num = 0, len = v.size();
    for (int i = 0; i < len; i ++) {
    	if (a[v[i]] == a[v[0]]) num ++;
    }
    int cn = len - num, p = len - 1;
    for (int i = 1; i <= n; i ++) {
    	if (!used[i]) {
    		res[i] = a[i];
    	} else {
    		res[i] = a[v[p --]];
    	}
    }
   	if (!is_sorted(res.begin() + 1, res.end())) cout << -1 << endl;
   	else cout << cn << endl;
    return ;
}

D Cyclic MEX

分析

对于一个确定的序列,确定其前缀mex可以通过O(n)的复杂度求得,考虑暴力,则是再O(n)枚举排列,肯定会T。考虑优化,从操作的特殊性入手,将序列想象成一个双端队列,每次则是弹掉队头插入队尾,这对于整个序列的前缀mex有如下几种变化:

  1. 队首元素的前缀mex弹掉
  2. 前缀mex小于p1的不变
  3. 前缀mex不小于p1的变为p1
  4. 队尾插入前缀mex为n

因此我们可以通过维护一个双端队列来O(n)求得答案,只要在每次按照上述变化更改信息即可。为了方便第3点的更改以及优化时间复杂度,我们可以将同前缀mex的元素压缩为pair,每次更新一个pair的值与次数即可

点击查看代码
void solve () {
    int n; cin >> n;
    vector<ll> p(n + 1);
    for (int i = 1; i <= n; i ++) cin >> p[i];
    vector<ll> pre_mex(n + 1, 0);
    deque<PLL> dq;
    ll mex = 0;
    ll s = 0;
    for (int i = 1; i <= n; i ++) {
    	pre_mex[p[i]] ++;
    	while (pre_mex[mex]) {
    		mex ++;
    	}
    	s += mex;
    	dq.push_back({mex, 1});
    }
    ll ans = s;
    for (int i = 1; i < n; i ++) {
    	s -= dq.front().fi;
    	dq.front().sc --;
    	if (!dq.front().sc) {
    		dq.pop_front();
    	}
    	PLL suf_mex = {p[i], 0};
    	while (!dq.empty() && dq.back().fi >= p[i]) {
    		s -= dq.back().fi * dq.back().sc;
    		suf_mex.sc += dq.back().sc;
    		dq.pop_back();
    	}
    	dq.push_back(suf_mex);
    	dq.push_back({n, 1});
    	s += suf_mex.fi * suf_mex.sc;
    	s += n;
    	ans = max(ans, s);
    }
    cout << ans << endl;
    return ;
}

E One-X

不太会 后面补

posted @ 2023-12-18 09:16  ComistryMo  阅读(58)  评论(0)    收藏  举报