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");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章