賽后總結:
TJ:隊友晚來了一會,於是我先做了簽到題。今天先做了A和B兩道簽到題,我特別蠢地做錯了B兩次(兩個小錯誤),然后emmm。隊友來了,和她們講了D題,然后金姐開始搞了。我和彭彭想了一會開始看F神奇序列。序列想了一會,覺得不是很難,找了一個交換數組最少次數的模板套上去就過了。然后我們換了一題,E題。E題一開始理解錯題意了,然后一起找規律計算。最后二十多分鍾我們找出來了,然后第一發超時,第二發金姐改了就過了。
我的隊友太強了嗚嗚。
PJW:剛到的時候,看了C題——CSL的密碼,感覺是DP,嗯。。好叭,不會寫。然后和譚總一起看了F ,我在糾結是否一個數組遞增,另一個數組遞減相乘的和是最小的,后來和譚總證了一下,應該是了。然后,又想一個數組遞增時求另一個數組遞減的交換次數和一個數組遞減時求另一個數組遞遞增的交換次數是不是一樣的,后來發現,應該是的。等譚總敲完,我還想着再找找樣例的時候,就已經過了!然后,幫ZJH小姐姐找D題字符串的樣例,成功卡住了小姐姐的代碼。等小姐姐和譚總看E題的時候,我自己敲了一遍字符串,后來也成功被小姐姐的樣例卡住了,放棄。最后一點時間,看了一些她們E題打表出來的數字,發現是有規律的!!然后,就是譚總和小姐姐敲、改E題了。
假以時日,譚總和小姐姐肯定能帶我飛 ->_<- !
JZH:剛到實驗室,譚總就說自己已經A了兩題,太強了!然后譚總給我講了D題的題意,然后就開始做D題了,打出來之后被彭彭想出來的樣例打到了。。。然后改了一下,還是不行,思考了一下,想不出來果斷放棄。看到F題被A了挺多的,就去看F題了,打了半個表,另外半個表不知道為啥,懶得打就手算了,事實證明我不能自己算。。。譚總可能差一點就找到規律了,但是因為我手算錯了,直到最后彭彭只看了前三個,發現了規律,我驗證了一下第四個,也是對的(事實上我有算錯了,結果陰差陽錯地規律找對了)
不能偷懶,打表技術有待提升!希望有一天,隊友能帶我躺着進final,嘻嘻~
A.CSL愛燙頭

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<map> #include<set> #include<vector> #include<cmath> #include<string> #include<queue> #include<iomanip> #include<algorithm> using namespace std; typedef long long LL; #define MAX 10005 int main() { int n; cin >> n; if (n < 1) cout << "None" << endl; else if (n == 1) cout << "XiZhiTang" << endl; else if (n == 2) cout << "YingHuaTang" << endl; else if (n >= 3) cout << "BigBoLang" << endl; system("pause"); return 0; }
B.CSL的英語考試

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<map> #include<set> #include<vector> #include<cmath> #include<string> #include<queue> #include<iomanip> #include<algorithm> using namespace std; typedef long long LL; #define MAX 10005 int p[MAX], visit[MAX] = { 0 }, la[MAX] = { 0 }; struct node { int id, people; double sum, num; }; node person[MAX], ans[MAX], p2[MAX]; bool comp(const struct node&a, const struct node&b) { if (a.sum == b.sum) return a.id < b.id; return a.sum > b.sum; } int Find(int x) { int temp = x; while (p[temp] != temp) temp = p[temp]; return temp; } void join(int x, int y) { int t1, t2; t1 = Find(x); t2 = Find(y); if (t1 != t2) { if (t1 > t2) { p[t1] = t2; } else p[t2] = t1; } } int main() { int n; scanf("%d", &n); map<char, int>a; for (int i = 0; i < 26; i++) { char c; cin >> c; a[c] = i; } for (int i = 0; i < n; i++) { char s1[1500], s2[1500]; cin >> s1 >> s2; int len1 = strlen(s1), len2 = strlen(s2); int len = min(len1, len2); int flag = -1; for (int i = 0; i < len; i++) { if (a[s1[i]] > a[s2[i]]) { flag = 1; break; } else if (a[s1[i]] < a[s2[i]]) { flag = 0; break; } } if (flag == -1 && len1 == len2) flag = -1; else if (flag== -1&&len == len1) flag = 0; else if (flag == -1&& len == len2) flag = 1; if (flag == 1) cout << ">" << endl; else if (flag == 0) cout << "<" << endl; else cout << "=" << endl; } system("pause"); return 0; }
C.CSL的密碼
題目意思很簡單。
簡單做法:給一段字符串,n為字符串長度,m為字符串作為密碼子串最短的長度。首先,長度為m~n的所有子串總數(不去重)為(n - m + 1)*(n - m + 2) / 2,然后我們開始一段段取,運用substr取對應長度的子串,放進set去重。如果set里有了,記錄多余重復的子串,然后最后答案減掉就好啦。
補充:題目里字符串是隨機出現的,所以長度越長,在長度長的情況下 幾乎可以認為都不同。
CSL聚聚說:為了讓不會后綴數組/自動機的同學可以過這題 強行出成了隨機。
我還是太菜了。

#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<map> #include<string> #include<vector> #include<stack> using namespace std; const int MAXN = 130000; #define inf 0x3f3f3f3f #define mm(a,b) memset(a,b,sizeof(a)) #define ll long long set<string>s[100]; int main() { ll n, m,count=0; string a; cin >> n >> m >> a; ll sum = (n - m + 1)*(n - m + 2) / 2; for (int i = m; i <= min(n,15LL); i++) { for (int j = 0; i + j - 1 < a.size(); j++) { string temp = a.substr(j, i); if (s[i].find(temp) != s[i].end()) count++; else s[i].insert(temp); } } cout << sum - count << endl; system("pause"); return 0; }
D:CSL的字符串
首先將字符串出現的每個字符都統計一遍數量,然后從左往右遍歷字符串,用數組模擬棧存答案字符串。
如果這個字符串被訪問過了就跳過。
如果遇到一個字符,比棧頂的元素小,並且棧頂的元素在后面還會出現,就把棧頂的彈出來,重新標記為未訪問過的。
把較小的存進棧里。

#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<map> #include<string> #include<vector> #include<ctime> using namespace std; const int MAXN = 130000; #define MAX_DISTANCE 0x3f3f3f3f #define mm(a,b) memset(a,b,sizeof(a)) #define ll long long #define SIGN(A) ((A > 0) ? 1 : -1) #define NO_DISTANCE 1000000 int main() { char s[MAXN]; int vis[MAXN] = { 0 }, num[MAXN] = {0}, stack[MAXN]; scanf("%s", s); int top = 0; int len = strlen(s); for (int i = 0; i < len; i++) { num[s[i]]++; } for (int i = 0; i < len; i++) { num[s[i]]--; if (vis[s[i]]) continue; while (top > 0 && stack[top] > s[i] && num[stack[top]] > 0) { vis[stack[top]] = 0; top--; } stack[++top] = s[i]; vis[s[i]] = 1; } for (int i = 1; i <= top; i++) { char ans =(char)stack[i]; cout << ans; } cout << endl; system("pause"); }
E.CSL的魔法
一開始看題目覺得挺難的。后來和隊友想了一下,覺得上下序列每一次都可以交換一對數字,和先排好上面,計算移動下面序列的位置的消費是相同的。
於是乎,套用了一個交換數列的最小次數的模板就過了。。。感謝出題組。

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<map> #include<set> #include<vector> #include<cmath> #include<string> #include<queue> #include<iomanip> #include<algorithm> #include<unordered_map> using namespace std; typedef long long LL; #define MAX 10005 int p[MAX], visit[MAX] = { 0 }, la[MAX] = { 0 }; struct node { int id, people; double sum, num; }; node person[MAX], ans[MAX], p2[MAX]; bool comp(const struct node&a, const struct node&b) { if (a.sum == b.sum) return a.id < b.id; return a.sum > b.sum; } int Find(int x) { int temp = x; while (p[temp] != temp) temp = p[temp]; return temp; } void join(int x, int y) { int t1, t2; t1 = Find(x); t2 = Find(y); if (t1 != t2) { if (t1 > t2) { p[t1] = t2; } else p[t2] = t1; } } struct number { int a, b; }x[150000]; bool cmp(number aa, number bb) { return aa.a > bb.a; } /*bool cmp2(num aa, num bb) { return aa.a > bb.a; }*/ int getMinSwaps(vector<int> &nums) { vector<int> nums1(nums); sort(nums1.begin(), nums1.end()); unordered_map<int, int> m; int len = nums.size(); for (int i = 0; i < len; i++) { m[nums1[i]] = i; } int loops = 0; vector<bool> flag(len, false); for (int i = 0; i < len; i++) { if (!flag[i]) { int j = i; while (!flag[j]) { flag[j] = true; j = m[nums[j]]; } loops++; } } return len - loops; } int main() { int n; cin >> n; for (int i = 0; i < n; i++) { cin >> x[i].a; //x2[i].a = x[i].a; } for (int i = 0; i < n; i++) { cin >> x[i].b; //x2[i].b = x[i].b; } sort(x, x + n, cmp); vector<int>num; for (int i = 0; i < n; i++) num.push_back(x[i].b); int res = getMinSwaps(num); cout << res << endl; system("pause"); return 0; }
F.CSL的神奇序列
規律題。先假設w=1,然后求出a1,a2,a3,a4,……。然后與n!和2^n進行運算。
算出來的例子:
n=1 1 1
n=2 3 3
n=3 15 3*5
n=4 105 3*5*7
n=4 945 3*5*7*9
……
然后初始化存進數組里,最后ans[n]*w取模輸出即可。

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<map> #include<set> #include<vector> #include<cmath> #include<string> #include<queue> #include<iomanip> #include<algorithm> #include<unordered_map> using namespace std; typedef unsigned long long ull; #define MAX 1000005 #define mod 998244353 ull a[MAX]; void init() { a[1] = 1; for (int i = 2; i <= 1000000; i++) { a[i] = (a[i - 1] * (2 * i - 1)) % mod; } } int main() { int w, q,n; cin >> w >> q; init(); while (q--) { int n; cin >> n; ull ans = a[n]; ans =(ans*w)%mod; cout << ans << endl; } system("pause"); return 0; }