2016 ACM-ICPC CHINA-Final

题目链接:https://vjudge.net/contest/259560#overview

A题:签到,略

B题:

C题:

D题:二分+贪心,主要是check函数怎么写的问题。我们采用贪心的策略,我们假设现在二分的值是mid,就是说能组成mid个tower,那么,我们先选择mid个最小的 balls,这个是最优的。因为如果我放着小的 ball 不选而去选大的,那么下一层所要求的 ball 就更严格了。选取完 mid 个小的之后我们就可以再对每个小的选取剩下的最接近其2倍长度的球,为什么选最接近的呢?道理和上面选小的 ball 是一样的。这样我们的贪心算法基本上就成型了。代码如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 typedef long long LL;
 5 const int maxn = 3e5 + 100;
 6 int T;
 7 int n, k;
 8 
 9 LL a[maxn];
10 int vis[maxn];
11 
12 
13 bool check(int mid)
14 {
15     for (int i = 1; i <= n; i++) vis[i] = 0;
16     for (int i = 1; i <= mid; i++) vis[i] = 1;
17 
18     int st = 1, ed = mid, flag = 0, maxx = ed;
19     for (int i = 1; i <= k-1; i++)
20     {
21         for (int j = st; j <= ed; j++)
22             if (vis[j])
23             {
24                 int pos = lower_bound(a+maxx+1,a+1+n,2*a[j])-a;
25                 //printf("%d %d\n",mid, a[pos]);
26 
27                 if (pos > n) { flag = 1; break; }
28                 vis[pos] = 1;
29                 maxx = max(maxx, pos);
30             }
31         if (flag) return false;
32         st = ed+1, ed = maxx;
33     }
34 
35     return true;
36 }
37 
38 
39 int main(){
40     scanf("%d",&T);
41     for(int t=1;t<=T;t++)
42     {
43         scanf("%d%d", &n, &k);
44         for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
45         sort(a+1, a+1+n);
46 
47         int l = 0, r = n/k, ans = 0;
48         while(l <= r)
49         {
50             int mid = (l+r)/2;
51             if (check(mid))
52                 ans = mid, l = mid+1;
53             else r = mid-1;
54         }
55 
56         printf("Case #%d: %d\n", t, ans);
57     }
58 return 0;
59 }
View Code

E题:简单贪心,这个题虽说是简答的贪心,但是过的人很少,因为这个题卡了精度,得使用 long double 才能过。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 
 7 using namespace std;
 8 const int maxn=100 + 10;
 9 const int Max = 100000;
10 long double spend[maxn];
11 
12 int main(){
13     int t;
14     scanf("%d", &t);
15     for (int ca = 1; ca <= t; ca++)
16     {
17         int n;
18         scanf("%d", &n);
19         for (int i = 1; i <= n; i++)
20         {
21             long double x, y;
22             char s;
23             cin >> x >> s >> y;
24             spend[i] = x/(y+x);
25         }
26 
27         int ans = 0;
28         long double tot = 1;
29         sort(spend+1, spend+1+n);
30 
31         for (int i = 1; i <= n; i++)
32             if (tot > spend[i]) tot -= spend[i], ans++;
33 
34         printf("Case #%d: %d\n", ca, ans);
35     }
36 return 0;
37 }
View Code

F题:

G题:

H题:思路,这个题一眼看上去就像一个 容斥 + dp 什么的,当时觉得很复杂,就没想了。赛后补题发现这个题目十分有意思。我们先来化简一下这个式子:

第二步到第三步:实际上 g = 0 的 Ag 一直累加到 NM 这个过程就是 NM 的方格中任意放 K 个数的过程之和。所以就是:K^(NM)。

第三步到第四步:我们重新思考一下 Ag 是什么,Ag 表示 有 g 个 great 值的填法总数之和,那么 g*Ag 是不是就可以这样理解,我们考虑每一个格子为 great 格,而其他位置我们不考虑。其他位置随便填,统计有重复的情况正好是我们需要的,因为我们的 Ag 本来就要乘以 g。

代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 const LL MOD = 1e9 + 7;
 6 
 7 LL qpow(LL a, LL b) {
 8     LL ans = 1;
 9     while(b) {
10         if(b&1) ans = ans*a%MOD;
11         a = a*a%MOD;
12         b >>=1;
13     }
14     return ans;
15 }
16 
17 int main() {
18     int T, ca = 1;
19     scanf("%d", &T);
20     while(T--) {
21         int N, M, K;
22         scanf("%d%d%d", &N, &M, &K);
23         LL ans = qpow(K, N*M);
24         for(int i = 1; i < K; ++i)
25             ans = (ans + qpow(i, N-1+M-1) * qpow(K, (N-1)*(M-1)) % MOD * N * M % MOD) % MOD;
26         if(N == 1 && M == 1) ans = (ans+1)%MOD;
27         printf("Case #%d: %lld\n", ca++, ans);
28     }
29     return 0;
30 }
View Code

I 题:

J题:

K题:

L题:签到,略

posted @ 2018-10-14 18:36  DyastySun  阅读(264)  评论(0编辑  收藏  举报