cumt2017第一次训练赛题解

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 (贪心)

题意:

思路:

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

 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 }

 

转载于:https://www.cnblogs.com/luosuo10/p/6662084.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值