2014 Multi-University Training Contest 1 部分题目解题报告

目前水平不够,只有简单题的题解,大神移步。

官方题解:  http://blog.sina.com.cn/s/blog_6bddecdc0102uy9g.html

 

HDOJ 4861 Couple doubi 

费马小定理推公式,(反正我是打表的=。=)

 

 

HDOJ 4864 Task

数据范围很大,无法用二分图匹配。转用贪心。

贪心的分析和简单证明:

对于任务,难度的影响因子是远远小于时间的,启发我们按时间为第一关键字,难度为第二关键字进行排序。除开金钱的因素,时间和难度是等同的限制条件。可以画一个二维坐标系,两轴对应时间和金钱,任务即是一个个点,而机器是一个个矩形,问题即是一个矩形能且仅能覆盖一个范围内的点,求覆盖最多的点数和价值。假设时间为x轴,我们从x轴的无穷端往原点扫,碰上了任务就拿时间足够,难度足够且难度最小的机器来匹配。因为是从时间最大开始扫的,所以显然答案的金钱最大化。同样,时间最大开始扫,机器的时间就不再是考虑的首要因素了,没必要留下时间比较大的机器,因为接下来的任务都比现在任务需要时间短,但接下来的任务难度可能更大,所以我们优先使用难度值小的机器。这种方法也满足匹配的任务最大化,还是比较显然的。

//程序学着标程敲的,不好意思。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<map>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 100100;
 8 int n, m, ans1;
 9 long long ans2;
10 struct stuff{
11     int t, d;
12 } a[maxn], b[maxn];
13 map<int, int> cnt;
14 bool cmp(stuff a, stuff b)
15 {
16     if (a.t == b.t) return a.d > b.d;
17     return a.t > b.t;
18 }
19 int main()
20 {
21     while(scanf("%d %d", &n, &m) != EOF)
22     {
23         for (int i = 0; i < n; i++)
24             scanf("%d %d", &a[i].t, &a[i].d);
25         for (int i = 0; i < m; i++)
26             scanf("%d %d", &b[i].t, &b[i].d);
27         sort(a, a+n, cmp);
28         sort(b, b+m, cmp);
29         ans1 = 0, ans2 = 0;
30         int j = 0;
31         cnt.clear();
32         map<int, int>::iterator it;
33         for (int i = 0; i < m; i++)
34         {
35             while(j < n && a[j].t >= b[i].t){        //时间足够的机器推入map中
36                 cnt[a[j].d]++;                        //难度为key值
37                 j++;
38             }
39             it = cnt.lower_bound(b[i].d);
40             if (it != cnt.end()){
41                 ans1 ++;
42                 ans2 += 500 * b[i].t + 2 * b[i].d;
43                 cnt[it->first] --;
44                 if (cnt[it->first] == 0)
45                     cnt.erase(it);
46             }
47         }
48         printf("%d %I64d\n", ans1, ans2);
49 //        printf("%d %lld\n", ans1, ans2);
50     }
51     return 0;
52 }        
View Code

 

 

HDOJ 4869 Turn the pokers

只要记录正面(反面)的个数,即可推出解。首先Σxi的奇偶性确定了正面个数的奇偶性,同时我们也发现答案会是连续的,所以找到最后的解的最大值和最小值,区间内相同奇偶性都是解。最大值最小值可以递推求出,需要分类讨论,细心一些。组合数有除法,要求逆元。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 typedef long long LL;
 7 const int mod = 1e9 + 9;
 8 const int maxn = 1e5;
 9 int n, m;
10 LL x, y;
11 int a[maxn + 10];
12 LL rev[maxn + 10];
13 int extgcd(int a, int b, LL &x, LL &y)
14 {
15     if (b == 0){
16         x = 1;
17         y = 0;
18         return a;
19     }
20     int gcd = extgcd(b, a % b, x, y);
21     LL t = x; x = y; y = t - (a/b) * y;
22     return gcd;
23 }
24 int main()
25 {
26     for (int i = 0; i <= maxn; i++){
27         extgcd(i, mod, x, y);
28         if (x < 0) x += mod; //x = (x + mod) % mod;
29         rev[i] = x; 
30     }
31     while(scanf("%d %d", &n, &m) != EOF)
32     {
33         for (int i = 0; i < n; i++)
34             scanf("%d", &a[i]);
35         int l = a[0], r = a[0];
36         for (int i = 1; i < n; i++){
37             int nl, nr;
38             if (a[i] <= l) nl = l - a[i];
39             else if (a[i] <= r) nl = (a[i] + l) % 2;
40             else nl = a[i] - r;
41             if (r + a[i] <= m) nr = r + a[i];
42             else if (l + a[i] <= m) nr = m - ((m - l + a[i]) % 2);
43             else nr = m - (a[i] - (m - l)); 
44             l = nl, r = nr;
45         }
46         int t = 0, sum = 0, tmp = 1;
47         if (l == 0) sum ++;
48         while (t < r){
49             t++;
50             tmp = (long long)(tmp) * (m-t+1) % mod * rev[t] % mod;
51             if (l <= t && t <= r && !((t+l)&1)){
52                 sum += tmp;
53                 sum %= mod;
54                 //if (sum < 0) sum += mod;
55             }
56         }
57         printf("%d\n", sum);
58     }
59     return 0;
60 }
View Code

 

 

HDOJ 4870 Rating

这题解法很多了。

1.记E(x, y)为高分号为x,低分号为y, 高分达到1000所需场数的期望, E(x, y) = 1 + pE(上升) + (1-p)E(下降)。得到大概200个方程,可以用高斯消元法解之。E(0, 0)为解。(也有一些大神用其他方法消元成功)

2.直接dp。其实两个账号并不会互相影响,考虑一个账号即可。详见:http://blog.csdn.net/u010089558/article/details/38051771

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 double dp[30], ans[30][30];
 6 double p;
 7 int main()
 8 {
 9     while(scanf("%lf", &p) != EOF)
10     {
11         memset(dp, 0, sizeof(dp));
12         memset(ans, 0, sizeof(ans));
13         dp[0] = 1/p; dp[1] = 1/p + (1-p)/p/p;
14         for (int i = 2; i <= 20; i++)
15             dp[i] = 1/p + (1-p)/p*(dp[i-2]+dp[i-1]);
16         ans[0][0] = 0; ans[1][0] = dp[0]; ans[1][1] = 2*dp[0];
17         for (int i = 1; i <= 20; i++){
18             ans[i][i] = ans[i][i-1] + dp[i-1];
19             ans[i+1][i] = ans[i][i] + dp[i];
20         }
21         printf("%.6lf\n", ans[20][19]);
22     }
23     return 0;
24 }
View Code

3.原来还有见到一个转换式子递推得到了解,现在还有好多题解要补不想找了。。

转载于:https://www.cnblogs.com/james47/p/3871805.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值