cumt训练赛题解

2017年4月3日

cumt2017春季——训练赛(1)

A.HihoCoder 1339 (dp)

思路:

  比较清晰呢,就是个dp吧。定义一下状态,dp[i][j]:前i个骰子,扔出点数和为j的方案数。然后不就很好写了嘛递推式,dp[i][j] = dp[i - 1][j - k](1<=k<=6)。

  好像题就做完了诶,可是窝wa了两发什么鬼。第一发爆int,第二发爆longlong,这里的trick就是方案数可能非常大,所以这题的应该把状态定义为dp[i][j]:前i个骰子,扔出点数和为j的概率。

  递推式大同小异。就完了?好像就这样,不过窝好像发现蒋理文用long double存了方案数也A了。。很骚很刚。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 double dp[105][605];
 4 int main()
 5 {
 6     int n, m;
 7     scanf("%d%d", &n, &m);
 8     for(int i = 1; i <= 6; i++)     dp[1][i] = 1.0 / 6;
 9     for(int i = 2; i <= n; i++)
10     {
11         for(int j = i; j <= 6 * n; j++)
12         {
13             for(int k = 1; k <= 6; k ++)
14             {
15                 if(j > k)   dp[i][j] += dp[i - 1][j - k] / 6.0;
16             }
17         }
18     }
19     printf("%.2f\n", 100.0 * dp[n][m]);
20
21     return 0;
22 }

B.UVA 11389 (贪心)

题意:

  有n个上午的任务和下午的任务,分配给司机,如果工作总时间超过d,超过的部分要给加班费;现在让你安排任务,问最小的加班分花费。

思路:

  排序一下,首尾加一下就好了。非常简单的贪心昂。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int mod = 1e9 + 7;
 4 const int maxn = 100 + 5;
 5 const int INF = 0x3f3f3f3f;
 6 typedef long long LL;
 7 typedef unsigned long long ull;
 8
 9 int day[maxn], night[maxn];
10
11 int main()
12 {
13     int n, d, r;
14     while(~scanf("%d%d%d", &n, &d, &r))
15     {
16         if(!n && !d && !r)  break;
17         for(int i = 0; i < n; i++)
18         {
19             scanf("%d", &day[i]);
20         }
21         for(int i = 0; i < n; i++)
22         {
23             scanf("%d", &night[i]);
24         }
25         sort(day, day + n, greater<int>());
26         sort(night, night + n, less<int>());
27
28         LL sum = 0;
29         for(int i = 0; i < n; i++)
30         {
31             int temp = day[i] + night[i];
32             if(temp > d)
33             {
34                 sum += (temp - d) * r;
35             }
36         }
37         cout << sum << "\n";
38     }
39     return 0;
40 }

C.HDU 1969 (二分)

思路:

  二分。然后这里有个trick,就是求π的时候,const double pi = acos(-1.0)。这样能够保证精度足够,而不是手写一个,除非你能背的很长很长2333.

  然后贴两个代码。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const double pi = acos(-1.0);
 4
 5 int cake[10000 + 5];
 6 int T, n, f;
 7 bool judge(double mid)
 8 {
 9     int ret = 0;
10     for(int i = 0; i < n; i++)
11     {
12         ret += int(cake[i]  * cake[i] / (mid * mid));
13     }
14     return ret >= f + 1;
15 }
16
17 int main()
18 {
19     scanf("%d", &T);
20     while(T--)
21     {
22         scanf("%d%d", &n, &f);
23         for(int i = 0; i < n; i++)
24         {
25             int x;
26             scanf("%d", &x);
27             cake[i] = x;
28         }
29
30         double lb = 0, rb = 1e5;
31         for(int i =0; i < 100; i++)
32         {
33             double mid = (lb + rb) / 2;
34             if(judge(mid))  lb = mid;
35             else rb = mid;
36         }
37         printf("%.4f\n", pi * lb * lb);
38     }
39     return 0;
40 }

  这个直接是二分的最后的结果。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const double pi = acos(-1.0);
 4
 5 double cake[10000 + 5];
 6 int T, n, f;
 7 bool judge(double mid)
 8 {
 9     int ret = 0;
10     for(int i = 0; i < n; i++)
11     {
12         ret += int(cake[i] / mid);
13     }
14     return ret >= f + 1;
15 }
16
17 int main()
18 {
19     scanf("%d", &T);
20     while(T--)
21     {
22         scanf("%d%d", &n, &f);
23         for(int i = 0; i < n; i++)
24         {
25             int x;
26             scanf("%d", &x);
27             cake[i] = pi * x * x;
28         }
29
30         double lb = 0, rb = pi * 2e4 * 2e4;
31         for(int i =0; i < 100; i++)
32         {
33             double mid = (lb + rb) / 2;
34             if(judge(mid))  lb = mid;
35             else rb = mid;
36         }
37         printf("%.4f\n", lb);
38     }
39     return 0;
40 }

D.UVA 11134 (经典贪心的变形)

题意:

  在一个n*n(1<=n<=5000)的棋盘上放置n个车,每个车都只能在给定的一个矩形里放置,使其n个车两两不在同一行和同一列,判断并给出解决方案。

思路:

  这个题比较难啊,这题本来打算拿来防AK的,第一次做的话会比较困难。

  首先我们思考一个简单的问题,如果把题目里的二维的改成一维的,你会不会做,就是有一行,让你放,每个车可以放一个区间[li,ri],问你能不能找到一种方案,使得每个车不在同一个格子里。

  针对这个问题是不是,这样贪心:枚举每个格子,记为i,那么是不是所有满足左端点li <= i的里头,挑一个右端点尽可能小的来放在这一个格子里面?,因为右端点越大,它后面可能可以放的格子越多,越小,可放的格子越小,所以我们这样贪心的来放。

  转换!这个问题可以分解成x方向上的问题,和相似的y方向上的问题。然后这个问题就转换成很经典的问题了,记不记得《挑战》奶牛擦防晒霜那题,经典的适配有上下边界的贪心。

 1 #include <stdio.h>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int mod = 1e9 + 7;
 5 const int maxn = 5000 + 5;
 6 const int INF = 0x3f3f3f3f;
 7 typedef long long LL;
 8 typedef pair<int, int>pii;
 9 typedef pair<LL, LL>pLL;
10 typedef unsigned long long ull;
11
12 struct node
13 {
14     int le, ri, order;
15     bool operator < (const node &other)const
16     {
17         return le < other.le || (le == other.le && ri < other.ri);
18     }
19 }x[maxn], y[maxn];
20 int ansx[maxn], ansy[maxn];
21
22 bool solve(int n, node z[], int ans[])
23 {
24     sort(z, z + n);
25     priority_queue<pii, vector<pii>, greater<pii>>que;
26     int cnt = 0, ret = 0;
27     for(int i = 1; i <= n; i++)
28     {
29         while(cnt < n && z[cnt].le <= i)
30         {
31             que.push({z[cnt].ri, z[cnt].order});
32             cnt++;
33         }
34         if(que.size() == 0) return false;
35
36         pii p = que.top();
37         if(p.first < i)    return false;
38         ans[p.second] = i;
39         que.pop();
40         ret++;
41     }
42     return ret == n;
43 }
44
45 int main()
46 {
47     int n;
48     while(~scanf("%d", &n))
49     {
50         if(n == 0)  break;
51         for(int i = 0; i < n; i++)
52         {
53             scanf("%d%d%d%d", &x[i].le, &y[i].le, &x[i].ri, &y[i].ri);
54             x[i].order = y[i].order = i;
55         }
56         if(solve(n, x, ansx) && solve(n, y, ansy))
57         {
58             for(int i = 0; i < n; i++)
59             {
60                 printf("%d %d\n", ansx[i], ansy[i]);
61             }
62         }
63         else    puts("IMPOSSIBLE");
64     }
65     return 0;
66 }

E.CodeForces 779A (water)

题意:

  有A组和B组,每组有n个人,A组里面每个人的分值为ai,B组里面每个人的分值为bi。1<=ai,bi<=5,至少双方要交换多少人才能使使A组里面每种分值的人要和B组里面一样多。

思路:

  先用一个cnt数组,记录一下每个分数的两组的人数差di。如果人数差di是奇数,false,那怎么也调不平呀对吧,因为3个人怎么也不可能分成两份。剩下的如果能顺利完成交换,是不是sigma{di}(di > 0) 和 sigma{di}(di < 0)要相等才能换成功呀,那是不是就是sigma{(abs(di)}是偶数呀。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int INF = 0x3f3f3f3f;
 4 const int maxn = 100 + 5;
 5 typedef long long LL;
 6 typedef pair<int, int>pii;
 7
 8 int n;
 9 int cnt[10];
10 int a[105], b[105];
11
12 int solve()
13 {
14     int ans = 0;
15     for(int i = 1; i <= 5; i++)
16     {
17         if(abs(cnt[i]) % 2 != 0) return -1;
18         ans += abs(cnt[i]) / 2;
19     }
20     if(ans % 2 == 1)    return  -1;
21     return ans / 2;
22 }
23
24 int main()
25 {
26     cin >> n;
27     for(int i = 0; i < n; i++)  cin >> a[i], cnt[a[i]]++;
28     for(int i = 0; i < n; i++)  cin >> b[i], cnt[b[i]]--;
29     cout << solve() << endl;
30     return 0;
31 }
时间: 2024-10-11 05:25:03

cumt训练赛题解的相关文章

周一训练赛题解

这次完全是水题大集合啊,希望大家A的开心: 前两个题是我找的,后两个是陶叔找的,另外因为我的偷懒,下面所有的代码都是陶叔亲自写的,十分感谢陶叔: 陶叔暑假为了大家的集训,牺牲了很多自己宝贵的时间,大家接下来要好好训练啊!!!! 废话少说,进入正题: Problem A      SPOJ QUEST5 签到题: 将所有的边按照右端点排个序,然后每次选择没有钉住的点,然后把这之后的所有与它相交的边全去掉: 代码: #include <cstdio> #include <cstring>

训练赛题解

突然想到好久以前做完这份题目没写题解.蛮来写写吧.很多细节已经忘记了.. 第一题 很简单的字符串比对是否b包含a.不包含就报NO,包含就YES..坑爹的第一次!!.把strlen放在了for循环里面..就超时了..超时了.. 注意:for里面的条件每次也会重新计算. A - All in All Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Submit Status Practice P

第三周训练赛题解

这次题目加强了搜索的练习,还有一些小技巧和基本方法,加了一道基础DP居然没人A确实是意料之外,C题的裸DFS也是很迷.蓝桥杯以爆搜为主,近期会加强搜索训练,做好准备. A: 给定一个整数n,将1~n排列成环使两两之间互质. DFS搜索所有可能的排列,输出. B: 问能否在恰好的时间从S->D 题目运用到了奇偶剪枝的方法, 根据题目,doggie必须在第t秒到达门口.也就是需要走t-1步.设doggie开始的位置为(sx,sy),目标位置为(ex,ey).如果abs(ex-x)+abs(ey-y)

2018.12.2 中国石油大学第一次新生训练赛题解

整理人: 周翔 A题:李继朋 B题:李继朋 H题:魏斯博 原文地址:https://www.cnblogs.com/QLU-ACM/p/10057831.html

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)

HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分相同,第一部分与第二部分对称. 现在给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法,求出以第i个点为中心的回文串长度,记录到数组p中 要满足题目所要求的内容,需要使得两个相邻的回文串,共享中间的一部分,也就是说,左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也是一样. 因为我们已经记录下来以

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&amp;#39;s problem(manacher+二分/枚举)

pid=5371">HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分同样,第一部分与第二部分对称. 如今给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法.求出以第i个点为中心的回文串长度.记录到数组p中 要满足题目所要求的内容.须要使得两个相邻的回文串,共享中间的一部分,也就是说.左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也

EXAM个人训练赛四

EXAM个人训练赛四 已完成 [x] A [x] D [x] E [x] F [x] J [x] K [x] I* 未完成 [x] B [x] C [x] G [x] H 签到水题 A J F A:英文字母有2426个 J:注意long long D:Transit Tree Path 我直接套了单源最短路的一个模板,有人用的是DFS,模板第一次用,记得是无向图. 代码又臭又长: #include<bits/stdc++.h> using namespace std; const int ma

EXAM个人训练赛五

EXAM个人训练赛五 已完成 [x] A [x] E [ ] K* [x] M* 未完成 [ ] C [ ] F 放弃没人做出来的题 A 要用ll,然后注意正方形的情况,细心一点 E 有点动态规划的感觉,状态的转移,不难,要注意不要漏掉状态 K 正解是DFS 然后用贪心数据弱的话能过,先排圆心 M 树状数组,可以维护前面有多少数比这个数小,然后通过相减也可以得出后面有多少数比它小,后面要用到容斥的思想 12xx(xx比1 2大)可以通过组合数算出,即前面比它小的选一个,后面比它大的选两个,然后相

1780 - 2019年我能变强组队训练赛第十八场

题目描述 wls有一个钟表,当前钟表指向了某一个时间. 又有一些很重要的时刻,wls想要在钟表上复现这些时间(并不需要依次复现).我们可以顺时针转动秒针,也可以逆时针转动秒针,分针和时针都会随着秒针按规则转动,wls想知道秒针至少转动多少角度可以使每个时刻至少都会被访问一次. 注意,时钟上的一种时针分针秒针的组合,可以代表两个不同的时间. 输入 第一行一个整数n代表有多少个时刻要访问. 第二行三个整数h,m,s分别代表当前时刻的时分秒. 最后n行每一行三个整数hi,mi,si代表每个要访问的时刻