目前水平不够,只有简单题的题解,大神移步。
官方题解: http://blog.sina.com.cn/s/blog_6bddecdc0102uy9g.html
HDOJ 4861 Couple doubi
费马小定理推公式,(反正我是打表的=。=)
HDOJ 4864 Task
数据范围很大,无法用二分图匹配。转用贪心。
贪心的分析和简单证明:
对于任务,难度的影响因子是远远小于时间的,启发我们按时间为第一关键字,难度为第二关键字进行排序。除开金钱的因素,时间和难度是等同的限制条件。可以画一个二维坐标系,两轴对应时间和金钱,任务即是一个个点,而机器是一个个矩形,问题即是一个矩形能且仅能覆盖一个范围内的点,求覆盖最多的点数和价值。假设时间为x轴,我们从x轴的无穷端往原点扫,碰上了任务就拿时间足够,难度足够且难度最小的机器来匹配。因为是从时间最大开始扫的,所以显然答案的金钱最大化。同样,时间最大开始扫,机器的时间就不再是考虑的首要因素了,没必要留下时间比较大的机器,因为接下来的任务都比现在任务需要时间短,但接下来的任务难度可能更大,所以我们优先使用难度值小的机器。这种方法也满足匹配的任务最大化,还是比较显然的。
//程序学着标程敲的,不好意思。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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 }
HDOJ 4869 Turn the pokers
只要记录正面(反面)的个数,即可推出解。首先Σxi的奇偶性确定了正面个数的奇偶性,同时我们也发现答案会是连续的,所以找到最后的解的最大值和最小值,区间内相同奇偶性都是解。最大值最小值可以递推求出,需要分类讨论,细心一些。组合数有除法,要求逆元。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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 }
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
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 }
3.原来还有见到一个转换式子递推得到了解,现在还有好多题解要补不想找了。。