CF R#579 Div.3题解

A题

找1的位置, 左右枚举就好。。

B题

如果面积固定, 正方形A的长比B的长要长, 那么它的宽一定比B的宽短, 把数组a排序后, 显然面积就是(a_1*a_n)。排序后从两遍向中间枚举就好。。

C题

求序列(a)中所有数的公约数的个数。
直接(O(nlogn))求出所有数的最小公约数(g), 再(O(sqrt{g}))枚举(g)的约数的个数即为答案。

D题

easy version

暴力枚举删的子串, 然后暴力判断, 更新答案。
时间复杂度(O(n^3))

hard version

暴力显然有很多繁琐的重复计算。
CF官方题解:

Let (rg_i) be such rightmost position (x) in (s) that the substring (t[i;|t|]) is the subsequence of (s[x;|s|]). We need values (rg_i) for all (i) from (1) to (|t|). We can calculate it just iterating from right to left over all characters of (s) and maintaining the pointer to the string (t) as in easy version.
Then let's iterate over all positions (i) from (1) to (|s|) and maintain the pointer (pos) as in the easy version which tells us the maximum length of the prefix of (t) we can obtain using only the substring (s[1;i)) (exclusively!). Suppose we want to remove the substring of (s) starting from (i). Then if (pos≤|t|) then let (rpos) be (rg_pos−1), otherwise let (rpos) be (|s|). (rpos) tells us the farthest rightmost character of the substring we can remove. So we can update the answer with the value (rpos−i+1) and go to the next position (and don't forget to increase (pos) if needed).

大意是先预处理出(rg)数组,(rg_i)为从(i)开始的(t)的后缀是从(rg_i)开始的(s)的后缀的子串。当然是最靠右的。这样我们匹配时, 枚举删除(s)左边界与当前(t)的匹配位置(pos)便可以(O(1))计算删除的右边界,更新答案即可。

时间复杂度是(O(n+m))

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
#include<cstdlib>
#include<ctime>

using namespace std;

#define FOR(a, b, c) for(int a = b; a <= c; a++)

const int mx = 2*1e5 + 5;
const int inf = 1<<30;

void fre() {
	freopen(".txt", "r", stdin);
	freopen(".txt", "w", stdout);
}

char s[mx], t[mx];
int n, m;
int rg[mx];

int main(){
    //fre();
    scanf("%s %s", s, t);
    int n = strlen(s), m = strlen(t);
    for(int i = m-1; i >= 0; i--) {
    	int pos = n-1;
    	if(i + 1 < m) pos = rg[i+1]-1;
    	while(s[pos] != t[i]) pos--;
    	rg[i] = pos;
	}
	
	int ans = 0;
	int pos = 0;
	FOR(i, 0, n-1) {
		int rpos = n-1;
		if(pos < m) rpos = rg[pos]-1;
		ans = max(ans, rpos - i + 1);
		if(pos < m && s[i] == t[pos]) pos++;
	}
	cout << ans << endl;
	return 0;
}

E题

贪心题。。
先从大到小排序, 依次考虑, 维护(W)为当前最大值, 如果当前(w_i+1) (<)(W), 便带上他, 并更新答案, 否则依次考虑(w_i) (w_i-1), 都不行就跳过。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
#include<cstdlib>
#include<ctime>

using namespace std;

#define FOR(a, b, c) for(int a = b; a <= c; a++)

const int mx = 1.5e5 + 5;
const int inf = 1<<30;

void fre() {
	freopen(".txt", "r", stdin);
	freopen(".txt", "w", stdout);
}

int n, a[mx];

int main(){
    //fre();
    cin >> n;
    FOR(i, 1, n) scanf("%d", &a[i]);
    sort(a+1, a+n+1); reverse(a+1, a+n+1);
    int Max = inf;
    int ans = 0;
    FOR(i, 1, n) {
    	int res = -1;
    	for(int x = 1; x >= -1; x--) {
    		if(a[i] + x > 0 && a[i] + x < Max) {
    			res = a[i] + x;
    			break;
			}
		}
		if(res == -1) continue;
		ans++;
		Max = res;
	}
	cout << ans << endl;
	return 0;
}

原文地址:https://www.cnblogs.com/Maktub-blog/p/11371821.html