赛后总结:
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; }