score:1336 (-45), pupil
Rank: 3313(又炸了,没啥好说的。。)
B.http://codeforces.com/contest/1215/problem/B
这个题万万没想到是dp,我的天,一开始直接上暴力,没仔细分析时间复杂度,估计是最近网络赛暴力惯了,没缓过神来。。。
分析见代码:
1 /* 2 设pos[i]表示以i为结尾的正区间,neg[i]表示以i为结尾的负区间。状态转移很容易了,见代码 3 这次真的wa到自闭了,后来改了改竟然又tle,真的自闭到家。。。自闭到家。。。。。 4 */ 5 #include <bits/stdc++.h> 6 using namespace std; 7 typedef long long ll; 8 const int maxn = 1e6; 9 ll pos[maxn], neg[maxn]; 10 11 int main() 12 { 13 int n; cin >> n; 14 int x; 15 ll maxpos, maxneg; 16 17 maxpos = maxneg = 0; 18 for (int i = 1; i <= n; i++) 19 { 20 scanf("%d", &x); 21 if (x < 0) 22 { 23 pos[i] = neg[i - 1]; 24 neg[i] = 1 + pos[i - 1]; 25 } 26 else 27 { 28 pos[i] = 1 + pos[i - 1]; 29 neg[i] = neg[i - 1]; 30 } 31 maxpos += pos[i]; 32 maxneg += neg[i]; 33 } 34 cout << maxneg << " " << maxpos << endl; 35 }
C.http://codeforces.com/contest/1215/problem/C
这道题也是,贪心想到了(而且很好想),但是情况没处理好,当ab和ba的情况加起来是奇数的时候输出-1,不然一定有解;
当时以为ab和ba都为奇数的时候还需要一个aa或者bb来做媒介,但其实不用,ab可以自己交换,然后再跟ba交换,花费两次。
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e6; 4 5 int vis[maxn]; 6 char a[maxn], b[maxn]; 7 8 int main() 9 { 10 int n; cin >> n; 11 int same, ab, ba; 12 vector<int> resa, resb; 13 14 same = ab = ba = 0; 15 scanf("%s%s", a + 1, b + 1); 16 for (int i = 1; i <= n; i++) 17 { 18 vis[i] = a[i] == b[i] ? 1 : a[i] == 'a' ? 2 : 3; 19 if (vis[i] == 1) 20 continue; 21 else if (vis[i] == 2) 22 resa.push_back(i); 23 else resb.push_back(i); 24 } 25 if ((resa.size() + resb.size()) & 1) return cout << -1 << endl, 0; 26 printf("%d ", resa.size() / 2 + resb.size() / 2 + (resa.size() % 2 ? 2 : 0)); 27 for (int i = 1; i < resa.size(); i += 2) 28 printf("%d %d ", resa[i - 1], resa[i]); 29 for (int i = 1; i < resb.size(); i += 2) 30 printf("%d %d ", resb[i - 1], resb[i]); 31 if (resa.size() % 2) 32 { 33 printf("%d %d ", resa[resa.size() - 1], resa[resa.size() - 1]); 34 printf("%d %d ", resb[resb.size() - 1], resa[resa.size() - 1]); 35 } 36 }
D.http://codeforces.com/contest/1215/problem/D
博弈论的题,博弈论做的比较少,但是基本都是分类讨论。这个题设两边的和sum1, sum2; 问号的和num1, num2;
①如果num1 == num2 && sum1 == sum2, B只需要每次在对面填充A的数就能赢;如果sum1 != sum2,A可以通过不断地在sum大的一方填充9就能赢
②如果num1 > num2
如果sum1 == sum2, A通过不断在num1填9就能赢。
如果sum1 > sum2, A通过不断在num1填9就能赢。
如果sum1 < sum2, A一定先把sum1用9填完,同时B也用9在对面填(防止差距更大),最后只要sum2留下的?数目是2的整数倍并且两个sum的差是9的整数倍,而且倍数相同B就能赢,不然B一定输。
这道题是后来补的,当时没做。。。
E.状压dp
分析:dp[i]表示状态i时所需要移动的最小的次数。dp[i]一定是由当前状态在加上一个数字(1-20)得来。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll inf = 0x3f3f3f3f3f3f3f3f; 5 const int maxn = 1e6; 6 ll cnt[21]; 7 ll f[21][21]; 8 ll dp[(1 << 20) + 10]; 9 10 int main() 11 { 12 int n; cin >> n; 13 for (int i = 1; i <= n; i++) 14 { 15 int x; scanf("%d", &x); 16 for (int i = 1; i <= 20; i++) 17 f[x][i] += cnt[i]; 18 cnt[x]++; 19 } 20 memset(dp, inf, sizeof(dp)); 21 dp[0] = 0; 22 for (int i = 1; i < (1 << 20); i++) 23 { 24 for(int j = 0; j < 20; j++) 25 if (i & (1 << j)) 26 { 27 int last = i ^ (1 << j); 28 ll res = 0; 29 for(int k = 0; k < 20; k++) 30 if ((1 << k) & last) 31 res += f[j + 1][k + 1]; 32 dp[i] = min(dp[i], dp[last] + res); 33 } 34 } 35 cout << dp[(1 << 20) - 1] << endl; 36 }
代码: