Codeforces Round #549 (Div. 2)
A、The Doors
思路:红色为本题的解题要点,也就是Mr.Block从左往右依次打开每一个门,当第一次能打开左边出口或者右边出口的最后一个门所在的打开位置index就是要找的最小下标k。注意:题目已经保证了左右出口至少各有一个门,也就是说k一定是给定01序列中最后一个元素(与其右边相邻元素值不同)所在的下标(不超过n-1),于是倒叙遍历简单判断一下即可。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 2e5+5; 27 const int inf = 0x3f3f3f3f; 28 29 int n, a[maxn]; 30 31 int main() { 32 while(cin >> n) { 33 for(int i = 0; i < n; ++i) cin >> a[i]; 34 for(int i = n - 2; ~i; --i) 35 if(a[i] ^ a[i + 1]) {cout << i + 1 << endl; break;} 36 } 37 return 0; 38 }
B、Nirvana
思路:dfs+数位dp思想。题意就是给定一个数字n,求1~n中哪个数字中所有位上的数字相乘之后乘积最大,求这个最大乘积。我们用借用数位dp的思想去枚举每一位,无脑暴力搜索,每搜到最后一位就取乘积最大值,要记忆化搜索,也就是记录已搜到的叶子节点状态,因为这个过程会重复计算大量相同子问题。注意:要多记录一个状态:上一位是否为上界!!!其余常规出牌即可。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 const double eps = 1e-6; 21 const double PI = acos(-1.0); 22 const int maxn = 1e5+5; 23 const int inf = 0x3f3f3f3f; 24 25 char str[15]; 26 int len, ans, mul, per, num[15]; 27 map<pair<int, bool>, bool> mp[15][10]; 28 29 /* pos:当前位置 30 * zero:pos前面拥有0的个数 31 * per:pos前面所有位上的数字的乘积 32 * now:上一位的数字是now 33 * limit:上一位数字是否为上界 34 */ 35 36 void dfs(int pos, int now, int zero, int per, bool limit) { 37 if(mp[pos][now][make_pair(per, limit)]) return; 38 mp[pos][now][make_pair(per, limit)] = true; 39 if(pos == len) { 40 ans = max(ans, per); 41 return; 42 } 43 int up = limit ? num[pos] : 9; 44 for(int j = up; ~j; --j) { 45 dfs(pos + 1, j, zero + !j, ((zero == pos && j) ? j : per * j), j == up && limit); 46 } 47 } 48 49 int main() { 50 while(cin >> str) { 51 len = strlen(str); 52 ans = 1; 53 for(int i = 0; i < 15; ++i) 54 for(int j = 0; j < 10; ++j) 55 mp[i][j].clear(); 56 for(int i = 0; i < len; ++i) ans *= (str[i] - '0'), num[i] = str[i] - '0'; 57 dfs(0, 0, 0, 1, true); // 初始状态:乘积值为1,上界为true 58 cout << ans << endl; 59 } 60 return 0; 61 }
C、Queen
思路:思维。由题可知,被删除的节点不但要不尊重其所有的祖先节点,而且与其相邻的所有儿子节点都要不尊重它。显然,每删除一个满足条件的节点,其所有儿子节点都会指向被删节点的父节点,这些儿子节点分别对应的所有儿子节点对各自的情况不变,又因为这些儿子节点之前本来就不尊重其所有祖先节点,所以现在指向被删去节点的父亲节点仍然不尊重它们,从这点可以得出我们应该去标记那些被儿子节点尊重的祖先节点,因为它们无论怎样都不会被删除,标记完之后升序遍历依次筛选即可。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 1e5+5; 27 const int inf = 0x3f3f3f3f; 28 29 int n, p, c[maxn]; 30 bool flag, vis[maxn]; 31 vector<int> ans; 32 33 int main() { 34 while(cin >> n) { 35 memset(c, 0, sizeof(c)); 36 memset(vis, false, sizeof(vis)); 37 ans.clear(); flag = false; 38 for(int i = 1; i <= n; ++i) { 39 // 节点i的父亲节点是p,c表示节点i是否尊重其所有祖先节点 40 cin >> p >> c[i]; 41 // 若p不是根节点,且节点i尊重其所有祖先节点,说明节点p至少有一个儿子节点尊重它,即节点p不会被删除 42 if(~p && !c[i]) vis[p] = true; 43 } 44 for(int i = 1; i <= n; ++i) 45 // 若节点i的所有儿子都不尊重它,并且它又不尊重其所有祖先节点,则应删除它 46 if(!vis[i] && c[i]) ans.push_back(i); 47 for(int j = 0, siz = ans.size(); j < siz; ++j) flag = true, cout << ans[j] << " \n"[j == siz - 1]; 48 if(!flag) puts("-1"); // 无需删除则输出-1 49 } 50 return 0; 51 }