BestCoder 1st Anniversary

5/6

这场打得好惨啊,不过学了新姿势,有收获就行,继续被虐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 }
代码君(nlog2n)

 

  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 }
代码君(nlogn)

 

posted @ 2016-05-25 12:31  zhenhao'Blog  阅读(227)  评论(0编辑  收藏  举报