Codeforces Educational Round #154 (Div.2) 题解

CF Edu #154 题解

上蓝场,当然要纪念一下。

A

Overview

做的太慢了。 1 1 1 分钟的题搞了 3 3 3 分钟。

Description

给一个数字串,求这个数字串中任意一个是质数的子序列

Idea

13 13 13 是质数, 31 31 31 也是质数。

所以答案肯定可以是 13 13 13 31 31 31
直接看一下顺序就可以了。

Code

int bucket[11];
repn(i, 0, s.length(), 1){
	bucket[s[i] - '0'] = i;
}
if(bucket[1] < bucket[3]) cout << 13 << endl;
else cout << 31 << endl;

B

Overview

出题者已经很仁慈了,放过了 O ( n 2 ) O(n^2) O(n2) 算法。

Description

给两个 01 串 s s s t t t,给定操作如下:

  • 取两个下标 i i i j j j
  • 如果 s i = s j s_i=s_j si=sj,则可以替换 ( i , j ) (i,j) (i,j) 内的所有数为 s i s_i si

问能否进行一次操作使得 s s s 变成 t t t

保证 s 1 = t 1 = 0 , s n = t n = 1 s_1=t_1=0, s_n=t_n=1 s1=t1=0,sn=tn=1

Idea

Solution 1

d i d_i di 为能否只操作 [ 1 , i ] [1,i] [1,i] 以内的数,让 s 1.. i = t 1.. i s_{1..i}=t_{1..i} s1..i=t1..i

就显然了。

Solution 2

结论:当且仅当存在 i i i,使得 s i = 0 s_i=0 si=0 s i + 1 = 1 s_{i+1}=1 si+1=1 t t t 同理),问题有解。

请自行证明。

Code

赛时只写了 Solution 1。

dp[0] = 1;
rep(i, 1, s.length(), 1){
	pre(j, i, 1, 1){
		if(s[i - 1] == s[j - 1] && t[i - 1] == t[j - 1] && s[i - 1] == t[i - 1])
			dp[i] += dp[j - 1];
	}
}
cout << (dp[s.length()] ? "YES" : "NO") << endl;

C

Overview

大水题。

Description

有一个串 s s s,每个字符 s i s_i si 代表一个操作:

  • s i s_i si+:在序列尾部(初始为空)加入任意整数。
  • s i s_i si-:删除序列尾部的数。
  • s i s_i si0/1:当 s i s_i si1,序列非降;否则,序列不非降。

s s s 是否可能存在。

Idea

显然,有序的数列删去还是有序,无序的数列加上还是无序。

直接用一个栈维护这个过程就行了。

Code

repn(i, 0, s.length(), 1){
	if(s[i] == '+'){
		if(st.empty() || st.top() != 1)
			st.push(2);
		else
			st.push(1);
	}
	else if(s[i] == '-'){
		if(st.empty()){
			cout << "NO" << endl;
			return;
		}
		st.pop();
	}
	else if(s[i] == '0'){
		if(st.size() < 2 || st.top() == 0){
			cout << "NO" << endl;
			return;
		}
		st.pop(); st.push(1);
	}
	else{
		if(!st.empty() && st.top() == 1){
			cout << "NO" << endl;
			return;
		}
		int cnt = 0;
		while(st.size() && st.top() != 0){
			st.pop(); cnt++;
		}
		while(cnt--) st.push(0);
	}
}
cout << "YES" << endl; 

D

Overview

好题。

Description

将一个数列通过以下操作排序:

  • 选择 l , r , m l,r,m l,r,m注意 m m m 可以是负数。
  • [ l , r ] [l,r] [l,r] 内的数乘上 m m m

求最小的操作数。

Idea

以下结论请自行证明。

显然,如果将 [ l , r ] [l,r] [l,r] 乘上一个相当大的数 k k k k 2 k^2 k2 k 3 k^3 k3,那么整个数列就变成了一个 k k k 进制数。

这样,只需找到连续的上升和下降子段就可以了。

Code

int a[n + 1], pre[n + 1], nxt[n + 1];
arrin<int>(a + 1, a + n + 1);
pre[0] = 0, pre[1] = 1, nxt[n] = 0;
rep(i, 2, n, 1){
	pre[i] = pre[i - 1];
	if(a[i] >= a[i - 1]) pre[i]++;
}
pre(i, n - 1, 1, 1){
	nxt[i] = nxt[i + 1];
	if(a[i] >= a[i + 1]) nxt[i]++;
}
int minv = MAXN;
rep(i, 1, n, 1){
	minv = min(minv, pre[i - 1] + nxt[i]);
}
cout << minv << endl;

你可能感兴趣的:(综合题题解,c++)