1. Maximal Values
很简单,从前往后扫,找满足的,O(n),很容易就过掉了。 maxn = 100. 没啥难点。
2. Bi-gram
用map统计个数,从前往后扫,每2个字符作为一个字符串,然后遍历map,存到vector里面,根据个数,字典序进行排序,也很简单。maxn = 100,不用考虑什么复杂的东西,没难度。
1 /* 2 ID: y1197771 3 PROG: test 4 LANG: C++ 5 */ 6 #include<bits/stdc++.h> 7 #define pb push_back 8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i) 9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl 10 typedef long long ll; 11 using namespace std; 12 typedef pair<int, int> pii; 13 const int maxn = 1e3 + 10; 14 struct node { 15 string v; 16 int s; 17 bool operator<(const node & x) const { 18 if(s == x.s) return v < x.v; 19 return s > x.s; 20 } 21 }; 22 void solve() { 23 string s; 24 cin >> s; 25 map<string, int> ma; 26 for (int i = 0; i < s.size() - 1; i ++) { 27 string cur = s.substr(i, 2); 28 ma[cur]++; 29 } 30 vector<node> v; 31 for (auto it : ma) { 32 v.pb({it.first, it.second}); 33 } 34 sort(v.begin(), v.end()); 35 for (auto i : v) 36 cout << i.v << endl; 37 38 } 39 int main() { 40 //freopen("test.in", "r", stdin); 41 //freopen("test.out", "w", stdout); 42 solve(); 43 return 0; 44 }
3. Sequence Filpping
理解题意很重要,给出许多区间,可以对这些区间内的数字进行翻转,这些区间可以任意选取。考虑数据范围很小,maxn = 8, maxm = 8, 考虑子集加全排列,复杂度是 2^8 * 8! * 8 = 82 575 360,在2s的时限内可以跑完,更上次的题目套路差不多。
这道题我做的时候,还以为只是子集,没考虑区间翻转顺序,以及后续debug的时候,忘记还原a数组,浪费了一些时间,这些小点都需要仔细注意。
1 /* 2 ID: y1197771 3 PROG: test 4 LANG: C++ 5 */ 6 #include<bits/stdc++.h> 7 #define pb push_back 8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i) 9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl 10 typedef long long ll; 11 using namespace std; 12 typedef pair<int, int> pii; 13 const int maxn = 1e3 + 10; 14 int n, m; 15 int a[20]; 16 int b[20]; 17 vector<pii> range; 18 void solve() { 19 cin >> n >> m; 20 for (int i = 1; i <= n; i++) cin >> a[i]; 21 int x, y; 22 for (int i = 0; i < m; i++) { 23 cin >> x >> y; 24 range.pb({x, y}); 25 } 26 int res = 0; 27 for (int i = 1; i <= n; i++) 28 res += i * a[i]; 29 for (int i = 0; i < (1 << m); i++) { 30 31 vector<int> p; 32 for (int j = 0; j < m; j++) { 33 if((1 << j) & i) { 34 p.pb(j); 35 //reverse(b + range[j].first, b + range[j].second + 1); 36 //cout << range[j].first << " " << range[j].second << endl; 37 } 38 } 39 sort(p.begin(), p.end()); 40 do { 41 for (int j = 1; j <= n; j++) b[j] = a[j]; 42 for (int x = 0; x < p.size(); x++) { 43 reverse(b + range[p[x]].first, b + range[p[x]].second + 1); 44 } 45 int s = 0; 46 for (int j = 1; j <= n; j++) { 47 s += j * b[j]; 48 //cout << b[j] << " "; 49 } 50 //cout <<endl; 51 res = max(res, s); 52 53 } while( next_permutation(p.begin(), p.end())); 54 55 } 56 cout << res << endl; 57 } 58 int main() { 59 //freopen("test.in", "r", stdin); 60 //freopen("test.out", "w", stdout); 61 solve(); 62 return 0; 63 }
4. Making a Number
题目描述很简单,一下就理解题意,然后我连例子都没仔细看,以为这不是状态dp么,记住过去的9个字母是什么,一步一步进行转移是什么不就完了,也没仔细考虑复杂度,然后结果肯定是失败的。应该先在纸上写清楚。大概算一下复杂度,还是太慌张,上来就想瞎码代码,这是错误的。
分析:分析例子,找规律,如果是状态转移dp,考虑一共的状态数是10! = 3 628 800,这个数字很大,1e5 * 10!,在2s的时间限制内是不行的,仔细想想,当长度超过10的时候,每个字符转移就是固定的,也就是后面所有的数字都确定了,为了满足每10个字符都不一致,因为最多10个字符,这个条件限制的非常好,比如现在是0123456789,下次的数字一定是01234567890,以至于后面的长度都确定了,01234567890123456789,这样没10个10个都是一样的,这样一想,那么结果就很简单了。
1. 当单词长度小于等于10个的时候,先判断合法性,有重复的数字,直接返回10, 然后统计出现的字符个数为a,单词长度为L,问号的个数为b, 然后结果就是 (10 - a)! / ((10 - a) - b)!. 也就是 A(10 - a, b);
2. 当单词长度大于10的,就是给的样例二,1???????9?????????4?,每10个字符进行一次划分。就像下面这样:
1???????9?
????????4?
10个长度为一组,因为前10个确定以后,后面的就直接重复就可以了,这里例子为0的原因是,上下第9个位置不能同时为9和4,然后,你应该知道怎么怎么做了。
就是每10个字符都归到前10个字符里面,如果是'?'直接跳过,如果是数字,判断前10个的相应位置上的字符,如果是数字,判断是否相等,不行等,直接返回0,相等则判断下一个字符,如果是问号,则把该位置字符置为同一字符。
最后根据前10的字符的情况,按照情况1的方式计算出结果。
我当时是这样想的,但是只过了12个例子,结束后又调试代码,才发现有一个下标写错了,感觉可以过得。
贴上我的代码,写的有点丑。
1 /* 2 ID: y1197771 3 PROG: test 4 LANG: C++ 5 */ 6 #include<bits/stdc++.h> 7 #define pb push_back 8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i) 9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl 10 typedef long long ll; 11 using namespace std; 12 typedef pair<int, int> pii; 13 const int maxn = 1e5 + 10; 14 string s; 15 ll ans = 0; 16 bool check(string s) { 17 if(s.size() <= 10) return 1; 18 string t = s.substr(0, 10); 19 for (int i = 10; i < s.size(); i+=10) { 20 if(i + 9 >= s.size()) { 21 for (int j = 0; i + j < s.size() && j < 10; j++) { 22 if(t[j] != '?' && s[i + j] != '?') { 23 if(t[j] != s[i + j]) return 0; 24 } else if((t[j] == '?' && s[i + j] != '?')) { 25 t[j] = s[i + j]; 26 } 27 } 28 } else { 29 for (int j = 0; j < 10; j++ ) { 30 if(t[j] != '?' && s[i + j] != '?') { 31 if(t[j] != s[i + j]) return 0; 32 } else if((t[j] == '?' && s[i + j] != '?')) { 33 t[j] = s[i + j]; 34 } 35 } 36 } 37 } 38 set<char> se; 39 for (char it : t) { 40 if(it == '?') continue; 41 se.insert(it); 42 } 43 ans = 1; 44 int d = 10 - se.size(); 45 //cout << d << " " << endl; 46 while(d) { 47 ans *= d; d--; 48 } 49 return 1; 50 } 51 void solve() { 52 while(cin >> s) { 53 if(s.size() <= 10) { 54 set<char> se; 55 for (auto t : s) { 56 if(t == '?') continue; 57 if(se.count(t)) { 58 cout << 0 << endl; 59 continue; 60 } 61 se.insert(t); 62 } 63 int n = s.size() - se.size(); 64 ll res = 1; 65 int d = 10 - se.size(); 66 while(n) { 67 res *= d; n--; d--; 68 } 69 cout << res << endl; 70 continue; 71 } else { 72 if(check(s)) { 73 cout << ans << endl; 74 } else { 75 cout << 0 << endl; 76 } 77 } 78 } 79 80 } 81 int main() { 82 freopen("test.in", "r", stdin); 83 //freopen("test.out", "w", stdout); 84 solve(); 85 return 0; 86 }
下面贴一下大神的代码:其实思路差不多
1 #include <iostream> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <map> 8 #include <bits/stdc++.h> 9 using namespace std; 10 11 int main() 12 { 13 freopen("test.in", "r", stdin); 14 string str; 15 16 while(cin >> str) { 17 map<int, int> umap; 18 int ans = 1, len = str.size(); 19 bool flag = false; 20 for(int i = 0; i < len; ++ i) { 21 if(str[i] != '?') { 22 if(umap.find(i % 10) != umap.end()) { 23 if(umap[i % 10] != str[i] - '0') { 24 flag = true; 25 break; 26 } 27 } 28 else { 29 str[i % 10] = str[i]; 30 umap[i % 10] = str[i] - '0'; 31 } 32 } 33 } 34 if(flag) cout << 0 << endl; 35 else { 36 int n = umap.size(); 37 int cnt = 0; 38 for(int i = 0; i < min(len, 10); ++ i) 39 if(str[i] == '?') 40 cnt ++; 41 for(int i = 10 - n, j = 1; j <= cnt; -- i, ++ j) 42 ans *= i; 43 cout << ans << endl; 44 } 45 } 46 47 48 return 0; 49 }
总结:
其实还是挺简单,头脑冷静下来仔细分析,还是可以很快做出来的。前3道是水题,最后一道稍微思考一下,就可以了。