Codeforces 988B 988C 题解

<Codeforces - 988B>

题意:

给定 n 个串,看这 n 个串能否形成一个序列,使得在序列中的任意位置的串都是他下一个串的连续子串,如果有,打印这个序列。

思路:

由于在某一位置的串是它下一个串的字串,所以这个序列里的串,首先就必须满足按照长度递增,所有按照长度进行结构体排序,然后再 O(n) 看位置 i 的串是否为位置 i + 1 的串的字串即可。这里要提一个黑科技,那就是如何判断一个串是否为另一个串的字串:

bool Jdg (string s1, string s2) {

        bool flg = 1;

        if( s2.find(s1) == -1) flg = 0;

        return flg;

}

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 133;
int n;

struct PP {
	string s;
} p[maxn];

bool cmp(PP x, PP y) {
	int l1 = x.s.length();
	int l2 = y.s.length();
	return l1 < l2;
}

bool Chk(string s1, string s2) {
	bool flag = 1;
	if(s2.find(s1) == -1) flag = 0;
	return flag;
}

int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> p[i].s;
	sort(p + 1, p + n + 1, cmp);
	bool flg = 1;
	for(int i = 1; i < n; i++) {
		if(Chk(p[i].s, p[i + 1].s)) continue;
		else {
			flg = 0; break;
		}
	}
	if(flg) {
		puts("YES");
		for(int i = 1; i <= n; i++) cout << p[i].s << endl;
	}
	else puts("NO");
	return 0;
}


<Codeforces - 988C>

题意:

给定 N 个序列,第 i 个序列有 n 个数。问是否存在两个序列 i 和 j ,使得在第 i 个序列和第 j 个序列中分别删除某个元素,使得剩下元素的和相等。

思路:

由于这题数据较大,二维数组根本就不够用,所以我选择用 vector 来存每次传进来的序列里 i 的每个元素 vec[ i ][ j ],其实这里vector的作用就相当于一个空间很大的二维数组,不必觉得不好理解。

简述一下我的思路,先开一个cnt[ ]数组存每个序列有多少个值,再对每次传进来的序列 i 中这 n 个元素的和sum,然后将sum存进Sum[ i ]记为第 i 个序列的元素和(cnt[ ]、Sum[ ] 这两个数组很重要,后面都要用到),再从这1 ~ n个元素中分别去掉第 j 个元素,使剩下的和为 sum - a[ j ],记为 mp[ j ]。

声明一个map类型的flg数组,用来将第 i 个序列里 每个元素 a[j]  产生的 mp[ j ](由于flg 存的是mp的值,即新的和,因此普通一维会越界,我就因为这里RE了几发,故将flg声明为map),标记为flg[ mp[ j ] ] = i,这样就能得到,在当前输入的第 num2 个串中删去某个值以后的那个新的和,与之前第几个序列(i的值)里删除某值以后产生的新的和相等,这也就是为什么不把 flg 开成 bool 型,因为要记录这个已经被标记过的 flg 是和之前哪个串的 flg 重复了。所以现在就知道了:产生相等和的两个串的编号num1, num2,以及当前输入进来的这个满足题意的串需要删除的那个元素的位置pos2,现在就需要知道pos1,即第num1个串需要删掉哪个值,才能产生这个想等的新和。

所以这时之前记的cnt[ ],Sum[ ] 就是为了保存住num1这个串的元素个数以及元素和,这样就可以枚举找pos1了,这时 vector就发挥作用了,进行如下操作即可:

for(int i = 0; i < cnt[num1]; i++) {
      if(Sum[num1] - vec[num1][i] == tmp) {
          pos1 = i + 1; break;
      }

}

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
vector <ll> vec[maxn]; //存每次输入进去的数组元素, 假装一下二维, 不用vector存不住
map <ll, ll> mp; //记录每个数组的和去掉当前位置元素以后的值
map <ll, ll> flg; //看新传进去的数组每个元素的mp值有没有和之前传入的重复
int cas, n;
ll a[maxn];
ll cnt[maxn]; //每次输入的数组元素个数
ll Sum[maxn]; //每次输入的数组元素的和
ll num1, pos1;
ll num2, pos2;

int main() {
	mp.clear();
	cin >> cas;
	bool chk = 0;
	int tmp = 0;
	for(int i = 1; i <= cas; i++) {
		cin >> n;
		cnt[i] = n;
		ll sum = 0;
		for(int j = 1; j <= n; j++) {
			cin >> a[j];
			vec[i].push_back(a[j]);
			sum += a[j];
		}
		Sum[i] = sum;
		for(int j = 1; j <= n; j++) mp[j] = sum - a[j];
		if(!chk) {
			for(int j = 1; j <= n; j++) {
				if(flg[mp[j]]) {
					chk = 1;
					num2 = i, pos2 = j;
					num1 = flg[mp[j]];
					tmp = mp[j];
					break;
				}
			}
		}
		for(int j = 1; j <= n; j++) flg[mp[j]] = i;
	}
	if(chk) {
		puts("YES");
		for(int i = 0; i < cnt[num1]; i++) {
			if(Sum[num1] - vec[num1][i] == tmp) {
				pos1 = i + 1; break;
			}
		}
		cout << num1 << " " << pos1 << endl;
		cout << num2 << " " << pos2 << endl;
	}
	else puts("NO");
}

猜你喜欢

转载自blog.csdn.net/ericgipsy/article/details/80710587