标签:
这场打得好惨啊,不过学了新姿势,有收获就行,继续被虐orz。。。。
题A hdu 5310
题意:可以一个买,可以一次买m个,价格分别为p和q,问你最少花多少钱买n个?
题解:水题,就三种情况!
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define xx first
8 #define yy second
9
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13
14 const ll inf = 1LL << 60;
15
16 int main() {
17 // freopen("case.in", "r", stdin);
18 int T;
19 cin >> T;
20 while (T--) {
21 int n, m, p, q;
22 scanf("%d%d%d%d", &n, &m, &p, &q);
23 ll res = inf;
24 res = min(res, 1ll * n * p);
25 res = min(res, 1ll * (n + m - 1) / m * q);
26 res = min(res, 1ll * n / m * q + 1ll * (n % m) * p) ;
27 printf("%I64d\n", res);
28 }
29 return 0;
30 }
题B hdu 5311
题意:给你一个串,问你能不能由三个子串组成“anniversary”?
题解:数据量小,想怎么暴力就怎么暴力,暴力枚举两个位置,将一个串分成三个部分,然后暴力将“anniversary”也暴力枚举两个位置分成三个部分,然后看每一部分是否有对应的子串,看起来好暴力,可就是过了(/▽╲)
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define xx first
8 #define yy second
9
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13
14 const int maxn = 1e2 + 10;
15 char s[maxn], t[maxn], tmp[3][maxn];
16 char str[maxn][3][20];
17 int cnt;
18
19 void init() {
20 strcpy(t, "anniversary");
21 cnt = 0;
22 for (int i = 1; i < 11; i++)
23 for (int j = i + 1; j < 11; j++) {
24 for (int k = 0; k < i; k++) str[cnt][0][k] = t[k];
25 for (int k = i; k < j; k++) str[cnt][1][k - i] = t[k];
26 for (int k = j; k < 11; k++) str[cnt][2][k - j] = t[k];
27 str[cnt][0][i] = str[cnt][1][j] = str[cnt][2][11] = 0;
28 // cout << str[cnt][0] << str[cnt][1] << str[cnt][2] << endl;
29 cnt++;
30 }
31 }
32
33 bool check() {
34 int n = strlen(s);
35 for (int i = 1; i < n; i++)
36 for (int j = i + 1; j < n; j++) {
37 for (int k = 0; k < i; k++) tmp[0][k] = s[k];
38 for (int k = i; k < j; k++) tmp[1][k - i] = s[k];
39 for (int k = j; k < n; k++) tmp[2][k - j] = s[k];
40 tmp[0][i] = tmp[1][j - i] = tmp[2][n - j] = 0;
41 // cout << tmp[0] << ‘ ‘ << tmp[1] << ‘ ‘ << tmp[2] << endl;
42 for (int k = 0; k < cnt; k++) {
43 bool ok = true;
44 for (int l = 0; l < 3 && ok; l++)
45 if (!strstr(tmp[l], str[k][l])) ok = false;
46 if (ok) return true;
47 }
48 }
49 return false;
50 }
51
52 int main() {
53 // freopen("case.in", "r", stdin);
54 init();
55 int T;
56 cin >> T;
57 while (T--) {
58 scanf("%s", s);
59 check() ? puts("YES") : puts("NO");
60 }
61 return 0;
62 }
题C hdu 5312
题意:给你一个序列,第i个元素是3 * n * (n - 1) + 1,然后问你最少需要多少个元素组成m?
题解:本来这道题应该打表找规律,但是贪心错了就不想做了(/▽╲)!
官方题解的做法是:先看一个行不行,再看两个行不行,都不行就找(m - ans) % 6 == 0,为什么可以这样呢?因为可以写成6 * (n * (n - 1)/ 2) + 1,注意到这个n * (n - 1)/ 2,有个神结论:任何一个数都可以用不超过三个三角形数表示,那么假设答案是k(k >= 3),然后就成为6 * (k个三角形数之和) + k = m,显然只要(m - k) % 6 == 0,得到一个数,他肯定可以被k个三角形数表示出来,所以这个结论是对的。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define xx first
8 #define yy second
9
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13
14 const int maxi = 1e9;
15 vector<int> v;
16
17 void init() {
18 for (int i = 1;; i++) {
19 int temp = 3 * i * (i - 1) + 1;
20 v.push_back(temp);
21 if (temp > maxi) break;
22 }
23 // cout << v.size() << endl;
24 }
25
26 bool check1(int x) {
27 if (*lower_bound(v.begin(), v.end(), x) == x) {
28 puts("1"); return true;
29 }
30 return false;
31 }
32
33 bool check2(int x) {
34 int i = 0, j = v.size() - 1;
35 while (i <= j) {
36 while (i <= j && v[i] + v[j] > x) --j;
37 if (i > j) break;
38 if (v[i] + v[j] == x) { puts("2"); return true; }
39 ++i;
40 }
41 return false;
42 }
43
44 int main() {
45 // freopen("case.in", "r", stdin);
46 init();
47 int T;
48 cin >> T;
49 while (T--) {
50 int n;
51 scanf("%d", &n);
52 if (!check1(n) && !check2(n)) {
53 for (int i = 3; i <= 8; i++) if ((n - i) % 6 == 0) {
54 printf("%d\n", i); break;
55 }
56 }
57 }
58 return 0;
59 }
题D hdu 5313
题意:给你一个图,然后问你最多可以添加多少条边形成一个完全二分图?
题解:这道题我想的方法是背包,然而超时了,因为O(n ^ 2)太大了,正解是biset优化。说下思路:
首先将一个连通子图染色0和1,然后记录这个0和1的数量,然后将每个连通块都记录下来,接下来问题就化成怎么将点组合到左边使得左边和右边的个数差异最小,因为最后假设左边有x个,右边有n - x个,然后答案就是x * (n - x)- m;所以这个差异最小的时候这个数值最大,这个显然可以用0-1背包来做,但是复杂度太大了,虽然侥幸一点的背包能过,但是还是学习正解好了,怎么用biset来优化这个东西呢?
开一个biset表示第i位表示这一个位是可以组成的,然后对于一个(x,y),如果选的是x的话,那么就是biset << x,如果选的是y的话,那么就是biset << y,然后只需要把这两个结果都或起来即可,一开始注意初始化第0个位置为1,联系一下dp的做法即可。其实之前做的一个浙大校赛有一道哈弗曼编码类似的,也是同样的优化思路。
1 /*zhen hao*/
2 #include <bits/stdc++.h>
3 using namespace std;
4
5 #define lson l, m, rt*2
6 #define rson m + 1, r, rt*2+1
7 #define xx first
8 #define yy second
9
10 typedef pair<int,int> pii;
11 typedef long long ll;
12 typedef unsigned long long ull;
13
14 const int maxn = 1e4 + 100, maxm = 1e5 + 100;
15 int n, m, e, head[maxn], color[maxn];
16 ll res, dp[2][maxn];
17
18 struct Edge {
19 int v, nx;
20 } edges[maxm];
21
22 void init() {
23 e = 0;
24 memset(head, -1, sizeof head);
25 }
26
27 void add_edge(int u, int v) {
28 edges[e] = (Edge){v, head[u]};
29 head[u] = e++;
30 }
31
32 void dfs(int u, int& c1, int& c2) {
33 if (color[u] == 1) c1++; else c2++;
34 for (int i = head[u]; ~i; i = edges[i].nx) {
35 int v = edges[i].v;
36 if (color[v] == -1) {
37 color[v] = 3 - color[u];
38 dfs(v, c1, c2);
39 }
40 }
41 }
42
43 vector<pii> p;
44
45 void slove() {
46 memset(color, -1, sizeof color);
47 p.clear();
48 for (int i = 1; i <= n; i++) if (color[i] == -1) {
49 int c1 = 0, c2 = 0;
50 color[i] = 1;
51 dfs(i, c1, c2);
52 p.push_back(make_pair(c1, c2));
53 }
54 bitset<10010> b;
55 b[0] = 1;
56 for (int i = 0; i < (int)p.size(); i++) {
57 b = (b << p[i].xx) | (b << p[i].yy);
58 }
59 int ans = 0;
60 for (int i = 1; i <= n; i++) if (b[i])
61 ans = max(ans, i * (n - i));
62 cout << ans - m << endl;
63 }
64
65 int main() {
66 // freopen("case.in", "r", stdin);
67 int T;
68 cin >> T;
69 while (T--) {
70 init();
71 scanf("%d%d", &n, &m);
72 for (int i = 0; i < m; i++) {
73 int u, v;
74 scanf("%d%d", &u, &v);
75 add_edge(u, v); add_edge(v, u);
76 }
77 slove();
78 }
79 return 0;
80 }
题E hdu 5314
题意:给你一颗树,找有多少对点满足最大值-最小值 <= D?
题解:显然树分治,听说可以用LCT水,然而并不会,所以只能用树分治。做的时候也是差不多想到正解了,但是错估复杂度了,没敢往下写,GG。。。。。
对于跨过重心的点对(u,v),有两种方法统计:
(1)常规做法:记录所有点到重心的最大值和最小值到一个vector中,然后先对x排个序,对于(xi,yi)找j < i,满足xi - yj <= D并且xi - yi <= D,因为可以确定xi一定是最大值的,但是最小值可能是yi,可能是yj,统计的时候可以先离散化,然后用树状数组即可。这是O(nlog2n)的做法,一下是少个log的做法:
(2)只需要对最小值由小到大排个序,然后对于当前点对(xi,yi)(其中xi是最小值,yi是最大值)统计(yi - D,0)的数量即可。为什么可以这样做呢?
首先我们分析为什么不能够这样做?因为对了x排序,找x >= yi - D的数量即保证了对于当前的点对的yi作为最大值,x作为最小值的点对满足。有可能存在x <= xj,然后yj比这个yi更大,也就是yj可能作为最大值使得这个东西不满足,等等,这个yj - xj是一定满足的(不满足的不加进vector中),那么不就不存在任何问题了,也就是如果这个yi作为最大值,那么一定满足,如果不作为最大值,那么找到yj作为最大值对应的xj肯定满足,所以并不需要树状数组离散化之后再来统计。这个完美地利用了点对的特点降了一个log。
1 /*zhen hao*/ 2 #include <bits/stdc++.h> 3 using namespace std; 4 5 #define lson l, m, rt*2 6 #define rson m + 1, r, rt*2+1 7 #define xx first 8 #define yy second 9 10 typedef pair<int,int> pii; 11 typedef long long ll; 12 typedef unsigned long long ull; 13 14 const int maxn = 1e5 + 100; 15 int n, D, e, head[maxn]; 16 17 struct Edge { 18 int v, nx; 19 } edges[maxn * 2]; 20 21 void init() { 22 e = 0; 23 memset(head, -1, sizeof head); 24 } 25 26 void add_edge(int u, int v) { 27 edges[e] = (Edge){v, head[u]}; 28 head[u] = e++; 29 } 30 31 int sz[maxn], vis[maxn]; 32 33 void dfs_s(int u, int p) { 34 sz[u] = 1; 35 for (int i = head[u]; ~i; i = edges[i].nx) { 36 int v = edges[i].v; 37 if (v == p || vis[v]) continue; 38 dfs_s(v, u); 39 sz[u] += sz[v]; 40 } 41 } 42 43 int dp[maxn], val[maxn]; 44 45 void dfs_t(int& s, int u, int p, int cnt) { 46 dp[u] = 0; 47 for (int i = head[u]; ~i; i = edges[i].nx) { 48 int v = edges[i].v; 49 if (v == p || vis[v]) continue; 50 dfs_t(s, v, u, cnt); 51 dp[u] = max(dp[u], sz[v]); 52 } 53 dp[u] = max(dp[u], cnt - sz[u]); 54 if (s == -1 || dp[u] < dp[s]) s = u; 55 } 56 57 struct Tree { 58 int C[maxn], sz; 59 inline int lowbit(int x) { 60 return x & (-x); 61 } 62 void init(int sz) { 63 this->sz = sz + 1; 64 for (int i = 0; i <= this->sz; i++) C[i] = 0; 65 } 66 void update(int x, int d) { 67 while (x <= sz) { 68 C[x] += d; 69 x += lowbit(x); 70 } 71 } 72 int sum(int x) { 73 int ret = 0; 74 while (x > 0) { 75 ret += C[x]; 76 x -= lowbit(x); 77 } 78 return ret; 79 } 80 } T; 81 82 vector<pii> x; 83 int c; 84 85 void dfs_c(int u, int p, int MAX, int MIN) { 86 MAX = max(val[u], MAX); 87 MIN = min(val[u], MIN); 88 x.push_back(make_pair(MAX, MIN)); 89 for (int i = head[u]; ~i; i = edges[i].nx) { 90 int v = edges[i].v; 91 if (v == p || vis[v]) continue; 92 dfs_c(v, u, max(MAX, val[v]), min(MIN, val[v])); 93 } 94 } 95 96 ll cal(int u, int p, int MIN, int MAX) { 97 x.clear(); 98 dfs_c(u, p, MIN, MAX); 99 sort(x.begin(), x.end()); 100 vector<int> tmp; 101 for (int i = 0; i < (int)x.size(); i++) tmp.push_back(x[i].yy); 102 sort(tmp.begin(), tmp.end()); 103 tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end()); 104 T.init(tmp.size()); 105 ll ret = 0; 106 for (int i = 0; i < (int)x.size(); i++) { 107 int xx = x[i].xx, yy = x[i].yy; 108 if (xx - yy <= D) { 109 int id = lower_bound(tmp.begin(), tmp.end(), xx - D) - tmp.begin(); 110 ret += i - T.sum(id); 111 } 112 int id = lower_bound(tmp.begin(), tmp.end(), yy) - tmp.begin() + 1; 113 T.update(id, 1); 114 } 115 return ret; 116 } 117 118 ll slove(int u) { 119 dfs_s(u, -1); 120 int cnt = sz[u], t = u; 121 u = -1; 122 dfs_t(u, t, -1, cnt); 123 vis[u] = 1; 124 ll ret = 0; 125 ret += cal(u, -1, val[u], val[u]); 126 for (int i = head[u]; ~i; i = edges[i].nx) { 127 int v = edges[i].v; 128 if (vis[v]) continue; 129 ret -= cal(v, u, val[u], val[u]); 130 } 131 for (int i = head[u]; ~i; i = edges[i].nx) { 132 int v = edges[i].v; 133 if (vis[v]) continue; 134 ret += slove(v); 135 } 136 return ret; 137 } 138 139 void gao() { 140 scanf("%d%d", &n, &D); 141 for (int i = 1; i <= n; i++) scanf("%d", val + i); 142 init(); 143 for (int i = 1; i < n; i++) { 144 int u, v; 145 scanf("%d%d", &u, &v); 146 add_edge(u, v); add_edge(v, u); 147 } 148 memset(vis, 0, sizeof vis); 149 ll res = slove(1); 150 printf("%I64d\n", res * 2); 151 } 152 153 int main() { 154 // freopen("case.in", "r", stdin); 155 int T; 156 cin >> T; 157 while (T--) gao(); 158 return 0; 159 }
1 /*zhen hao*/ 2 #include <bits/stdc++.h> 3 using namespace std; 4 5 #define lson l, m, rt*2 6 #define rson m + 1, r, rt*2+1 7 #define xx first 8 #define yy second 9 10 typedef pair<int,int> pii; 11 typedef long long ll; 12 typedef unsigned long long ull; 13 14 const int maxn = 1e5 + 100; 15 int n, D, e, head[maxn]; 16 17 struct Edge { 18 int v, nx; 19 } edges[maxn * 2]; 20 21 void init() { 22 e = 0; 23 memset(head, -1, sizeof head); 24 } 25 26 void add_edge(int u, int v) { 27 edges[e] = (Edge){v, head[u]}; 28 head[u] = e++; 29 } 30 31 int sz[maxn], vis[maxn]; 32 33 void dfs_s(int u, int p) { 34 sz[u] = 1; 35 for (int i = head[u]; ~i; i = edges[i].nx) { 36 int v = edges[i].v; 37 if (v == p || vis[v]) continue; 38 dfs_s(v, u); 39 sz[u] += sz[v]; 40 } 41 } 42 43 int dp[maxn], val[maxn]; 44 45 void dfs_t(int& s, int u, int p, int cnt) { 46 dp[u] = 0; 47 for (int i = head[u]; ~i; i = edges[i].nx) { 48 int v = edges[i].v; 49 if (v == p || vis[v]) continue; 50 dfs_t(s, v, u, cnt); 51 dp[u] = max(dp[u], sz[v]); 52 } 53 dp[u] = max(dp[u], cnt - sz[u]); 54 if (s == -1 || dp[u] < dp[s]) s = u; 55 } 56 57 pii S[maxn]; 58 int c; 59 60 void dfs_c(int u, int p, int MAX, int MIN) { 61 MAX = max(val[u], MAX); 62 MIN = min(val[u], MIN); 63 if (MAX - MIN <= D) S[c++] = make_pair(MIN, MAX); 64 for (int i = head[u]; ~i; i = edges[i].nx) { 65 int v = edges[i].v; 66 if (v == p || vis[v]) continue; 67 dfs_c(v, u, max(MAX, val[v]), min(MIN, val[v])); 68 } 69 } 70 71 ll cal(int u, int p, int MIN, int MAX) { 72 c = 0; 73 dfs_c(u, p, MIN, MAX); 74 sort(S, S + c); 75 ll ret = 0; 76 for (int i = 0; i < c; i++) { 77 int p = lower_bound(S, S + c, make_pair(S[i].yy - D, 0)) - S; 78 ret += i - p; 79 } 80 return ret; 81 } 82 83 ll slove(int u) { 84 dfs_s(u, -1); 85 int cnt = sz[u], t = u; 86 u = -1; 87 dfs_t(u, t, -1, cnt); 88 vis[u] = 1; 89 ll ret = 0; 90 ret += cal(u, -1, val[u], val[u]); 91 for (int i = head[u]; ~i; i = edges[i].nx) { 92 int v = edges[i].v; 93 if (vis[v]) continue; 94 ret -= cal(v, u, val[u], val[u]); 95 } 96 for (int i = head[u]; ~i; i = edges[i].nx) { 97 int v = edges[i].v; 98 if (vis[v]) continue; 99 ret += slove(v); 100 } 101 return ret; 102 } 103 104 void gao() { 105 scanf("%d%d", &n, &D); 106 for (int i = 1; i <= n; i++) scanf("%d", val + i); 107 init(); 108 for (int i = 1; i < n; i++) { 109 int u, v; 110 scanf("%d%d", &u, &v); 111 add_edge(u, v); add_edge(v, u); 112 } 113 memset(vis, 0, sizeof vis); 114 ll res = slove(1); 115 printf("%I64d\n", res * 2); 116 } 117 118 int main() { 119 // freopen("case.in", "r", stdin); 120 int T; 121 cin >> T; 122 while (T--) gao(); 123 return 0; 124 }
标签:
原文地址:http://www.cnblogs.com/zhenhao1/p/5526568.html