题单一览

时间:20201028~20201101

✔hdu1050 活动安排变形

✔hdu4864 不错的题

✔poj1328 活动安排变形

✔poj1089 区间覆盖

✔hdu4911 逆序对

✔hdu1425 快速排序思想

部分总结

大部分都是比较典型的贪心题目,现在拿出来复习一下基本的算法思想。因为过于依赖STL,快排都忘了怎么写(是的我快排WA了几发)。

HDU1050

本来想的是多次的活动安排问题模型,但实际上并不是。活动安排要求尽可能多参加,而这个题目要求全部参加时间尽可能少。

因此,我们可以举出按活动安排模型排序(按结束时间排序)的反例:

反例

主要就是这里需要注意一下,其他都是很常规的排序贪心。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <bits/stdc++.h>
#define maxn 4005
using namespace std;
int t, n;
struct seg{
int lf;
int rt;
int val;
} s[maxn];
bool cmp(const seg &A, const seg &B){
return A.lf < B.lf;
//return A.rt < B.rt;
}
int main(void)
{
scanf("%d", &t);
while(t--)
{
memset(s, 0, sizeof(s));

int num = 0, ans = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &s[i].lf, &s[i].rt);
if(s[i].lf > s[i].rt)
swap(s[i].lf, s[i].rt);
}
sort(s+1, s+n+1, cmp);
while(num < n)
{
//printf("%d\n", num);
int nrt = 0;
for(int i = 1; i <= n; i++)
{
if(s[i].val) continue;
//printf("%d %d %d\n", s[i].lf, s[i].rt, s[i].val);
if(s[i].lf & 1 && s[i].lf > nrt)
{
s[i].val = 1;
nrt = s[i].rt;
num++;
}
if(s[i].lf % 2 == 0 && s[i].lf > nrt + 1)
{
s[i].val = 1;
nrt = s[i].rt;
num++;
}
}
ans += 10;
}
printf("%d\n", ans);
}
return 0;
}

HDU4864

的确是很妙的一道贪心题。

首先观察数据范围,确定$x_i$的影响远远大过$y_i$,由此确定排序方法。

(当然你也可以直接用计算的函数来排序)

然后,妙的地方来了。

排序好后,顺序枚举每一个任务,每次枚举开始时,将可使用的机器(最大使用时间达到要求)的等级用一个桶存起来。

完成这一步后,由当前任务的等级向最高等级枚举,若发现存在这样的机器还未被使用,则调用,统计完答案后跳出循环,保证了调用的是尽可能菜的机器。同时由于已经排了序,因此机器的最大使用时间也是符合要求的。

这样子可以大大压缩时间复杂度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <bits/stdc++.h>
#define maxn 300005
using namespace std;
int n, m, c[maxn];
struct des{
int maxt;
int level;
} a[maxn], t[maxn];
bool cmp(const des &A, const des &B){
if(A.maxt != B.maxt) return A.maxt > B.maxt;
return A.level > B.level;
}
int main(void)
{
while(~scanf("%d %d", &n, &m))
{
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; i++)
scanf("%d %d", &a[i].maxt, &a[i].level);
for(int i = 1; i <= m; i++)
scanf("%d %d", &t[i].maxt, &t[i].level);
sort(a+1, a+n+1, cmp);
sort(t+1, t+m+1, cmp);
long long ans = 0, num = 0;
for(int i = 1, j = 1; i <= m; i++)
{
while(a[j].maxt >= t[i].maxt && j <= n)
{
c[a[j].level]++;
j++;
}
for(int k = t[i].level; k <= 100; k++)
{
if(c[k])
{
c[k]--;
ans += 500 * t[i].maxt + 2 * t[i].level;
num++;
break;
}
}
}
printf("%lld %lld\n", num, ans);
}
return 0;
}

HDU1425

排序板子题。

主要踩了快速排序的一个坑。

具体看代码注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void qsort(int lf, int rt){
if(lf >= rt) return;
/*
* 这个位置若改为int mid = (lf + rt) / 2,会WA掉一些点
* 因为在下面排序的过程中,a[mid]是可能会改变。
*/
int mid = a[(lf + rt) / 2];
int i = lf, j = rt;
while(i <= j)
{
while(a[i] < mid) i++;
while(a[j] > mid) j--;
if(i <= j)
{
swap(a[i], a[j]);
i++;
j--;
}
}
qsort(lf, j);
qsort(i, rt);
}

下阶段目标

本来想先看图论的,不过想了一下还是先看看简单数学。

主要包含,快速幂,GCD,LCM,exGCD,不定方程,同余方程,逆元,基础生成函数,入门博弈论等。

在数学复习完后,需要去复习一下图论的基本内容,然后去刷字符串的基本内容,再然后巩固好这些基础题后,去刷一下高级数据结构(Splay这种)和计算几何,希望人没事,大概。

下一阶段数学回顾题单:


hdu1061,求$n^n$的末尾数字

hdu3117,矩阵快速幂算Fib数列

hdu6030,递推数列转为矩阵,再进行快速幂取模

hdu1576,拓展欧几里得

hdu2588,欧拉函数复习

hdu5656,有关GCD的动态规划

poj2689,区间素数板子

hdu3792,素数打表可做

hdu2841,容斥原理

hdu4135,容斥原理

hdu1028,递归/DP/生成函数

hdu1521,指数型生成函数

hdu5673,卡特兰数+逆元

hdu4035,树+期望DP

hdu2999,SG函数

hdu4111,记忆化搜索+SG函数

hdu1527,威佐夫博弈