pku2380 Balancing the Scale :
上海的題??吹竭@題我立刻想到了以前做過的一道:sumset。用類似的方法,可以把任意4個數連接起來作為一個整體。然后分別放到兩個數組中,排序。之后從左到右分別檢驗左右是否相等(具體參考程序),注意使用位運算壓縮。
PKU1637 Sightseeing tour
老題了,混合圖的歐拉回路。
首先是預判,然后建圖。我的建圖方法是這樣的:
對于每個點都有自己的入度需求量,將其作為到T的容量。
對于每個無向邊看一個點,都可以提供1的入度,所以連接S的1容量的邊。
最后把無向邊連向其能夠提供入度的2個點。
PKU1848 Tree
很好的樹形DP,由于題目不允許兩點之間連第3邊(題目沒說-_-|||) 所以要3個狀態才能搞定。
PKU3042 Grazing on the Run
類似于 PKU2671 Jimmy's Bad Day
很好的區間DP模型。關鍵代碼如下
PKU2795 Exploring Pyramids
DP。用到了樹形DP的思想(算是吧?)
關鍵代碼如下:
PKU3111 K Best
好題。
看到了之后,會想到這個和曾經一道最有比率生成樹非常相似。用類似的方法進行二分求解是正途。但是到這里還是復雜度太高(二分里面有一個排序),考慮到只要排序出前K個元素,可以考慮部分排序(用的是快排的原理)。
PKU1932 XYZZY
bellman_Ford求負權最短路, 當有負權圈的時候可以檢測到.
對于這道題而言,我們可以建模為:
加HP: 負權點
減HP: 正權點
將點權化作邊權后(可以拆點,或者直接將點權加入入邊)run一次bellman_ford
bellman_ford中只擴展標號<100的點
如果無負權圈,顯然只需判終點的最短路是否<100
如果有負權圈,就判bellman_ford是否可能到達任何一個負權圈上的點.
PKU3411 Paid Roads
初看像狀態壓縮DP,寫完之后才發現有環。
其實只需要拆點轉化成最短路模型就可以了。
上海的題??吹竭@題我立刻想到了以前做過的一道:sumset。用類似的方法,可以把任意4個數連接起來作為一個整體。然后分別放到兩個數組中,排序。之后從左到右分別檢驗左右是否相等(具體參考程序),注意使用位運算壓縮。
1
#include <string.h>
2
#include <algorithm>
3
#include <stdio.h>
4
5
using namespace std;
6
7
#define two(x) (1<<(x))
8
#define contain(S, x) (((S)&(two(x))) != 0)
9
10
const int MAX = 43680;
11
12
struct Node
{
13
int mask, w;
14
Node()
{}
15
Node(int mm, int ww)
{
16
mask = mm;
17
w = ww;
18
}
19
}A[MAX];
20
21
int cnt[two(16)];
22
23
bool operator<(const Node& a, const Node& b)
{
24
return a.w < b.w;
25
}
26
27
int a[16], nA;
28
29
void solve()
{
30
int beg = 0, end = 0, i, j, k;
31
for(i = 1; i < nA; ++i)
{
32
if(A[i].w != A[i-1].w)
{
33
for(j = beg; j <= end; ++j)
34
for(k = j+1; k <= end; ++k)
35
if((A[j].mask&A[k].mask) == 0)
36
cnt[A[j].mask|A[k].mask]++;
37
beg = end = i;
38
}
39
else
40
end = i;
41
}
42
int ans = 0;
43
for(i = 0; i < two(16); ++i)
{
44
if(cnt[i] != 0 && cnt[(two(16)-1)^i] != 0)
45
ans += cnt[i] * cnt[(two(16)-1)^i];
46
}
47
printf("%d\n", ans/2);
48
}
49
50
int main()
{
51
52
// freopen("t.in", "r", stdin);
53
54
int i, j, k, m, tc = 0;
55
for(tc = 1; ; tc++)
{
56
scanf("%d", &a[0]);
57
if(a[0] == 0)
58
break;
59
for(i = 1; i < 16; ++i)
60
scanf("%d", a+i);
61
nA = 0;
62
for(i = 0; i < 16; ++i)
63
for(j = 0; j < 16; ++j) if(j != i)
64
for(k = 0; k < 16; ++k) if(k != i && k != j)
65
for(m = 0; m < 16; ++m) if(m != i && m != j && m != k)
{
66
int t = two(i)+two(j)+two(k)+two(m);
67
A[nA++] = Node(t, 4*a[i]+3*a[j]+2*a[k]+a[m]);
68
}
69
sort(A, A+nA);
70
71
memset(cnt, 0, sizeof(cnt));
72
printf("Case %d: ", tc);
73
solve();
74
75
}
76
77
return 0;
78
}
79
80
81
82

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

57

58

59

60

61

62

63

64

65



66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

PKU1637 Sightseeing tour
老題了,混合圖的歐拉回路。
首先是預判,然后建圖。我的建圖方法是這樣的:
對于每個點都有自己的入度需求量,將其作為到T的容量。
對于每個無向邊看一個點,都可以提供1的入度,所以連接S的1容量的邊。
最后把無向邊連向其能夠提供入度的2個點。
PKU1848 Tree
很好的樹形DP,由于題目不允許兩點之間連第3邊(題目沒說-_-|||) 所以要3個狀態才能搞定。
PKU3042 Grazing on the Run
類似于 PKU2671 Jimmy's Bad Day
很好的區間DP模型。關鍵代碼如下
1
2
dp[0][n-1][0] = dp[0][n-1][1] = 0;
3
4
for(i = n-1; i >= 1; --i)
{
5
for(j = 0; j + i - 1 <= n-1; ++j)
{
6
k = j+i-1;
7
if( Beg >= j && Beg <= k )
{
8
if(j > 0)
{
9
dp[j][k][0] = Min(dp[j][k][0], dp[j-1][k][0] + (a[j]-a[j-1])*(j+n-1-k));
10
dp[j][k][1] = Min(dp[j][k][1], dp[j-1][k][0] + (a[k]-a[j-1])*(j+n-1-k));
11
}
12
if(k < n-1)
{
13
dp[j][k][0] = Min(dp[j][k][0], dp[j][k+1][1] + (a[k+1]-a[j])*(j+n-1-k));
14
dp[j][k][1] = Min(dp[j][k][1], dp[j][k+1][1] + (a[k+1]-a[k])*(j+n-1-k));
15
}
16
// for(int l = 0; l < 2; ++l) printf("dp[%d][%d][%d] = %d\n", j, k, l, dp[j][k][l]);
17
}
18
}
19
}
20

2

3

4



5



6

7



8



9

10

11

12



13

14

15

16

17

18

19

20

PKU2795 Exploring Pyramids
DP。用到了樹形DP的思想(算是吧?)
關鍵代碼如下:
1
for(i = 0; i < len; ++i)
2
dp[i][i] = 1;
3
4
for(l = 3; l <= len; l += 2)
{
5
for(i = 0; i+l-1<=len-1; ++i)
{
6
j = i+l-1;
7
dp[i][j] = 0;
8
if(s[i] == s[j])
{
9
for(k = i+2; k <= j; k+=2)
{
10
dp[i][j] = (int)((dp[i][j] + (long long)dp[i+1][k-1] * dp[k][j])%MAX);
11
}
12
// printf("dp[%d][%d] = %d\n", i, j, dp[i][j]);
13
}
14
}
15
}
16

2

3

4



5



6

7

8



9



10

11

12

13

14

15

16

PKU3111 K Best
好題。
看到了之后,會想到這個和曾經一道最有比率生成樹非常相似。用類似的方法進行二分求解是正途。但是到這里還是復雜度太高(二分里面有一個排序),考慮到只要排序出前K個元素,可以考慮部分排序(用的是快排的原理)。
PKU1932 XYZZY
bellman_Ford求負權最短路, 當有負權圈的時候可以檢測到.
對于這道題而言,我們可以建模為:
加HP: 負權點
減HP: 正權點
將點權化作邊權后(可以拆點,或者直接將點權加入入邊)run一次bellman_ford
bellman_ford中只擴展標號<100的點
如果無負權圈,顯然只需判終點的最短路是否<100
如果有負權圈,就判bellman_ford是否可能到達任何一個負權圈上的點.
PKU3411 Paid Roads
初看像狀態壓縮DP,寫完之后才發現有環。
其實只需要拆點轉化成最短路模型就可以了。