CodeForces Round #585 (Div 2)

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\n", 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\n", resa[i - 1], resa[i]);
29     for (int i = 1; i < resb.size(); i += 2)
30         printf("%d %d\n", resb[i - 1], resb[i]);
31     if (resa.size() % 2)
32     {
33         printf("%d %d\n", resa[resa.size() - 1], resa[resa.size() - 1]);
34         printf("%d %d\n", 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 }

 

 

 

代码:

posted @ 2019-09-16 12:41  滚烫的青春  阅读(414)  评论(1编辑  收藏  举报