<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");
}