新智认知”杯上海高校程序设计竞赛暨第十七届上海大学程序设计春季联赛 比赛总结
赛后总结:
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里有了,记录多余重复的子串,然后最后答案减掉就好啦。
#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; }
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,……。然后与阶乘和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; }