【 2013 Multi-University Training Contest 1 】

HDU 4602 Partition

f[i]表示和为i的方案数。已知f[i]=2i-1

dp[i]表示和为i,k有多少个。那么dp[i]=dp[1]+dp[2]+...+dp[i-1]+f[i-k]。

考虑与f有关的项:

f[n-k]是答案的一部分,即2n-k-1是答案的一部分。

把与dp有关的项:

令s[i-1]=dp[1]+dp[2]+...+dp[i-1],那么s[n-1]是答案的一部分。

s[i]=s[i-1]+dp[i],又dp[i]=s[i-1]+f[i-k]。推出s[i]=2*s[i-1]+f[i-k],dp[k]=s[k]=1。

可以推出s[n-1]=2n-k-1+(n-k-1)*2n-k-2

 1 #include<iostream>
 2 typedef long long LL;
 3 LL MOD = 1000000007LL;
 4 using namespace std;
 5 LL powmod(LL a, LL b) {
 6     LL ans;
 7     a %= MOD;
 8     for (ans = 1; b; b >>= 1) {
 9         if (b & 1) {
10             ans *= a;
11             ans %= MOD;
12         }
13         a *= a;
14         a %= MOD;
15     }
16     return ans;
17 }
18 int main() {
19     int T;
20     LL n, k;
21     LL ans;
22     cin >> T;
23     while (T--) {
24         cin >> n >> k;
25         if (k > n) {
26             ans = 0;
27         } else if (k == n) {
28             ans = 1;
29         } else if (n - k == 1) {
30             ans = 2;
31         } else if (n - k == 2) {
32             ans = 5;
33         } else {
34             ans = powmod(2, n - k - 1)
35                     + (n - k - 1) * powmod(2, n - k - 2) % MOD;
36             ans += powmod(2, n - k - 1);
37             ans = (ans % MOD + MOD) % MOD;
38         }
39         cout << ans << endl;
40     }
41     return 0;
42 }
View Code

HDU 4604 Deque

枚举第i个数,假设它最早出现且在队列里,那么以i为起点的最长非降子序列一定在队列里(push_back),以i为起点的最长非升子序列也一定在队列里(push_front)。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define MAXN 100010
 4 #define oo 123456789
 5 using namespace std;
 6 int arr[MAXN];
 7 int up[MAXN], down[MAXN], cnt[MAXN];
 8 int st[MAXN], top;
 9 void LIS(int n, int dp[]) {
10     int i;
11     int pos;
12     top = -1;
13     for (i = 0; i < n; i++) {
14         if (top < 0 || st[top] <= arr[i]) {
15             st[++top] = arr[i];
16             dp[i] = top + 1;
17         } else {
18             pos = upper_bound(st, st + top + 1, arr[i]) - st;
19             st[pos] = arr[i];
20             dp[i] = pos + 1;
21         }
22         cnt[i] = min(cnt[i],
23                 upper_bound(st, st + top + 1, arr[i])
24                         - lower_bound(st, st + top + 1, arr[i]));
25     }
26 }
27 int main() {
28     int T;
29     int n;
30     int i;
31     int ans;
32     scanf("%d", &T);
33     while (T--) {
34         scanf("%d", &n);
35         for (i = 0; i < n; i++) {
36             scanf("%d", &arr[i]);
37             cnt[i] = oo;
38         }
39         reverse(arr, arr + n);
40         LIS(n, up);
41         for (i = 0; i < n; i++) {
42             arr[i] = -arr[i];
43         }
44         LIS(n, down);
45         ans = 0;
46         for (i = 0; i < n; i++) {
47             ans = max(ans, up[i] + down[i] - cnt[i]);
48         }
49         printf("%d
", ans);
50     }
51     return 0;
52 }
View Code

HDU 4605 Magic Ball Game

统计树上一个节点到根,权值大于/小于某个数的个数:数状数组/线段树。

离线处理询问,对所有w的值离散化。

从树根开始DFS,第一次到达一个节点时,回答所有询问。

向儿子DFS时,更新往左/右的数状数组。

最后一次离开一个节点时,还原现场。

  1 #pragma comment(linker, "/STACK:1024000000,1024000000")
  2 
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<vector>
  7 #include<set>
  8 #define MAXN 200010
  9 using namespace std;
 10 int w[MAXN], tmp[MAXN];
 11 struct node {
 12     int pre;
 13     int next[2];
 14     void init() {
 15         pre = -1;
 16         next[0] = next[1] = -1;
 17     }
 18 } tree[MAXN];
 19 struct Ask {
 20     int weight;
 21     int pos;
 22 };
 23 vector<Ask> q[MAXN];
 24 pair<int, int> res[MAXN];
 25 bool stop[MAXN];
 26 multiset<int> myset;
 27 inline int lowbit(int x) {
 28     return x & -x;
 29 }
 30 void update(int arr[], int i, int val) {
 31     for (; i < MAXN; i += lowbit(i)) {
 32         arr[i] += val;
 33     }
 34 }
 35 int sum(int arr[], int i) {
 36     int ans;
 37     for (ans = 0; i > 0; i -= lowbit(i)) {
 38         ans += arr[i];
 39     }
 40     return ans;
 41 }
 42 int left[MAXN], right[MAXN];
 43 void dfs(int x) {
 44     int i, j;
 45     for (i = 0; i < (int) q[x].size(); i++) {
 46         j = q[x][i].pos;
 47         if (myset.count(q[x][i].weight)) {
 48             res[j].first = -1;
 49         } else {
 50             res[j].first = sum(right, q[x][i].weight - 1);
 51             res[j].second = 3 * sum(left, q[x][i].weight - 1)
 52                     + 3 * sum(right, q[x][i].weight - 1);
 53 
 54             res[j].second += sum(left, MAXN - 1) - sum(left, q[x][i].weight);
 55             res[j].second += sum(right, MAXN - 1) - sum(right, q[x][i].weight);
 56         }
 57     }
 58 
 59     myset.insert(w[x]);
 60     if (tree[x].next[0] != -1) {
 61         update(left, w[x], 1);
 62         dfs(tree[x].next[0]);
 63         update(left, w[x], -1);
 64     }
 65     if (tree[x].next[1] != -1) {
 66         update(right, w[x], 1);
 67         dfs(tree[x].next[1]);
 68         update(right, w[x], -1);
 69     }
 70     myset.erase(myset.find(w[x]));
 71 }
 72 int main() {
 73     int T;
 74     int n, m;
 75     int i, j;
 76     int u, a, b;
 77     int size;
 78     Ask ask;
 79     scanf("%d", &T);
 80     while (T--) {
 81         scanf("%d", &n);
 82         size = 0;
 83         for (i = 1; i <= n; i++) {
 84             scanf("%d", &w[i]);
 85             tree[i].init();
 86             q[i].clear();
 87             tmp[size++] = w[i];
 88         }
 89         scanf("%d", &m);
 90         while (m--) {
 91             scanf("%d%d%d", &u, &a, &b);
 92             tree[u].next[0] = a;
 93             tree[u].next[1] = b;
 94             tree[a].pre = u;
 95             tree[b].pre = u;
 96         }
 97         scanf("%d", &m);
 98         for (i = 0; i < m; i++) {
 99             scanf("%d%d", &u, &ask.weight);
100             ask.pos = i;
101             q[u].push_back(ask);
102             tmp[size++] = ask.weight;
103         }
104         sort(tmp, tmp + size);
105         size = unique(tmp, tmp + size) - tmp;
106         for (i = 1; i <= n; i++) {
107             w[i] = lower_bound(tmp, tmp + size, w[i]) - tmp + 1;
108             for (j = 0; j < (int) q[i].size(); j++) {
109                 q[i][j].weight = lower_bound(tmp, tmp + size, q[i][j].weight)
110                         - tmp + 1;
111             }
112         }
113         myset.clear();
114         memset(left, 0, sizeof(left));
115         memset(right, 0, sizeof(right));
116         for (i = 1; i <= n; i++) {
117             if (tree[i].pre < 0) {
118                 dfs(i);
119                 break;
120             }
121         }
122         for (i = 0; i < m; i++) {
123             if (res[i].first < 0) {
124                 puts("0");
125             } else {
126                 printf("%d %d
", res[i].first, res[i].second);
127             }
128         }
129     }
130     return 0;
131 }
View Code

HDU 4606 Occupy Cities

预处理出任意两个城市的最短距离。

若士兵可以从一个城市i到达另一个城市j,且i比j先占领,才连i->j的边。

二分士兵背包的容量,可以得到一个有向图。二分条件是有向图的最小路径覆盖与士兵人数的关系。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cmath>
  5 #define MAXN 310
  6 #define MAXM 10010
  7 #define oo 123456789
  8 #define eps 1e-6
  9 using namespace std;
 10 
 11 struct point {
 12     double x, y;
 13 };
 14 struct line {
 15     point a, b;
 16 };
 17 point city[MAXN];
 18 line barr[MAXN];
 19 
 20 double dis[MAXN][MAXN];
 21 int first[MAXM], next[MAXM], v[MAXM], e;
 22 int order[MAXN];
 23 int cx[MAXN], cy[MAXN];
 24 bool mk[MAXN];
 25 
 26 int dbcmp(double x, double y) {
 27     if (fabs(x - y) < eps) {
 28         return 0;
 29     } else {
 30         return x > y ? 1 : -1;
 31     }
 32 }
 33 bool zero(double x) {
 34     return fabs(x) < eps;
 35 }
 36 double dist(point p1, point p2) {
 37     return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
 38 }
 39 double xmult(point p1, point p2, point p0) {
 40     return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
 41 }
 42 int dots_inline(point p1, point p2, point p3) {
 43     return zero(xmult(p1, p2, p3));
 44 }
 45 int same_side(point p1, point p2, line l) {
 46     return xmult(l.a, p1, l.b) * xmult(l.a, p2, l.b) > eps;
 47 }
 48 int same_side(point p1, point p2, point l1, point l2) {
 49     return xmult(l1, p1, l2) * xmult(l1, p2, l2) > eps;
 50 }
 51 inline int dot_online_in(point p, point l1, point l2) {
 52     return zero(xmult(p, l1, l2)) && (l1.x - p.x) * (l2.x - p.x) < eps
 53             && (l1.y - p.y) * (l2.y - p.y) < eps;
 54 }
 55 int dot_online_in(point p, line l) {
 56     return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x) * (l.b.x - p.x) < eps
 57             && (l.a.y - p.y) * (l.b.y - p.y) < eps;
 58 }
 59 int intersect_in(point u1, point u2, point v1, point v2) {
 60     if (!dots_inline(u1, u2, v1) || !dots_inline(u1, u2, v2))
 61         return !same_side(u1, u2, v1, v2) && !same_side(v1, v2, u1, u2);
 62     return dot_online_in(u1, v1, v2) || dot_online_in(u2, v1, v2)
 63             || dot_online_in(v1, u1, u2) || dot_online_in(v2, u1, u2);
 64 }
 65 
 66 void floyd(int n) {
 67     int i, j, k;
 68     for (k = 0; k < n; k++) {
 69         for (i = 0; i < n; i++) {
 70             for (j = 0; j < n; j++) {
 71                 dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
 72             }
 73         }
 74     }
 75 }
 76 inline void addEdge(int x, int y) {
 77     v[e] = y;
 78     next[e] = first[x];
 79     first[x] = e++;
 80 }
 81 int path(int x) {
 82     int y;
 83     for (int i = first[x]; i != -1; i = next[i]) {
 84         y = v[i];
 85         if (!mk[y]) {
 86             mk[y] = true;
 87             if (cy[y] == -1 || path(cy[y])) {
 88                 cx[x] = y;
 89                 cy[y] = x;
 90                 return 1;
 91             }
 92         }
 93     }
 94     return 0;
 95 }
 96 int match(int n) {
 97     int res, i;
 98     memset(cx, -1, sizeof(cx));
 99     memset(cy, -1, sizeof(cy));
100     for (res = i = 0; i < n; i++) {
101         if (cx[i] == -1) {
102             memset(mk, false, sizeof(mk));
103             res += path(i);
104         }
105     }
106     return res;
107 }
108 int main() {
109     int T;
110     int n, m, p;
111     int i, j, k;
112     double low, high, mid;
113     scanf("%d", &T);
114     while (T--) {
115         scanf("%d%d%d", &n, &m, &p);
116         for (i = 0; i < n; i++) {
117             scanf("%lf%lf", &city[i].x, &city[i].y);
118         }
119         for (i = 0; i < m; i++) {
120             scanf("%lf%lf%lf%lf", &barr[i].a.x, &barr[i].a.y, &barr[i].b.x,
121                     &barr[i].b.y);
122         }
123         for (i = 0; i < n; i++) {
124             scanf("%d", &order[i]);
125             order[i]--;
126         }
127 
128         for (i = 0; i < n + m + m; i++) {
129             for (j = 0; j <= i; j++) {
130                 dis[i][j] = dis[j][i] = oo;
131             }
132         }
133 
134         for (i = 0; i < n; i++) {
135             dis[i][i] = 0;
136             for (j = i + 1; j < n; j++) {
137                 for (k = 0; k < m; k++) {
138                     if (intersect_in(city[i], city[j], barr[k].a, barr[k].b)) {
139                         break;
140                     }
141                 }
142                 if (k >= m) {
143                     dis[i][j] = dis[j][i] = dist(city[i], city[j]);
144                 }
145             }
146         }
147 
148         for (i = 0; i < n; i++) {
149             for (j = 0; j < m; j++) {
150                 for (k = 0; k < m; k++) {
151                     if (j == k) {
152                         continue;
153                     }
154                     if (intersect_in(city[i], barr[j].a, barr[k].a,
155                             barr[k].b)) {
156                         break;
157                     }
158                 }
159                 if (k >= m) {
160                     dis[i][n + (j << 1)] = dis[n + (j << 1)][i] = dist(city[i],
161                             barr[j].a);
162                 }
163                 for (k = 0; k < m; k++) {
164                     if (j == k) {
165                         continue;
166                     }
167                     if (intersect_in(city[i], barr[j].b, barr[k].a,
168                             barr[k].b)) {
169                         break;
170                     }
171                 }
172                 if (k >= m) {
173                     dis[i][n + (j << 1 | 1)] = dis[n + (j << 1 | 1)][i] = dist(
174                             city[i], barr[j].b);
175                 }
176 
177             }
178         }
179 
180         for (i = 0; i < m; i++) {
181             for (j = 0; j < i; j++) {
182                 for (k = 0; k < m; k++) {
183                     if (k == i || k == j) {
184                         continue;
185                     }
186                     if (intersect_in(barr[i].a, barr[j].a, barr[k].a,
187                             barr[k].b)) {
188                         break;
189                     }
190                 }
191                 if (k >= m) {
192                     dis[n + (i << 1)][n + (j << 1)] = dis[n + (j << 1)][n
193                             + (i << 1)] = dist(barr[i].a, barr[j].a);
194                 }
195 
196                 for (k = 0; k < m; k++) {
197                     if (k == i || k == j) {
198                         continue;
199                     }
200                     if (intersect_in(barr[i].a, barr[j].b, barr[k].a,
201                             barr[k].b)) {
202                         break;
203                     }
204                 }
205                 if (k >= m) {
206                     dis[n + (i << 1)][n + (j << 1 | 1)] =
207                             dis[n + (j << 1 | 1)][n + (i << 1)] = dist(
208                                     barr[i].a, barr[j].b);
209                 }
210 
211                 for (k = 0; k < m; k++) {
212                     if (k == i || k == j) {
213                         continue;
214                     }
215                     if (intersect_in(barr[i].b, barr[j].a, barr[k].a,
216                             barr[k].b)) {
217                         break;
218                     }
219                 }
220                 if (k >= m) {
221                     dis[n + (i << 1 | 1)][n + (j << 1)] = dis[n + (j << 1)][n
222                             + (i << 1 | 1)] = dist(barr[i].b, barr[j].a);
223                 }
224 
225                 for (k = 0; k < m; k++) {
226                     if (k == i || k == j) {
227                         continue;
228                     }
229                     if (intersect_in(barr[i].b, barr[j].b, barr[k].a,
230                             barr[k].b)) {
231                         break;
232                     }
233                 }
234                 if (k >= m) {
235                     dis[n + (i << 1 | 1)][n + (j << 1 | 1)] = dis[n
236                             + (j << 1 | 1)][n + (i << 1 | 1)] = dist(barr[i].b,
237                             barr[j].b);
238                 }
239             }
240         }
241 
242         floyd(n + m + m);
243 
244         low = 0;
245         high = oo;
246         while (dbcmp(low, high) < 0) {
247             e = 0;
248             memset(first, -1, sizeof(first));
249             mid = (low + high) * 0.5;
250             for (i = 0; i < n; i++) {
251                 for (j = i + 1; j < n; j++) {
252                     if (dbcmp(dis[order[i]][order[j]], mid) <= 0) {
253                         addEdge(order[i], order[j]);
254                     }
255                 }
256             }
257             if (n - match(n) > p) {
258                 low = mid;
259             } else {
260                 high = mid;
261             }
262         }
263 
264         printf("%.2lf
", mid);
265 
266     }
267     return 0;
268 }
View Code

HDU 4607 Park Visit

最长链上的边走一次,其他边都必须走两次。

dp[i][0]表示以i为根的子树的最大深度,dp[i][1]表示以i为根的子树的次大深度。

答案就是max(dp[i][0]+dp[i][1])。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MAXN 200010
 5 using namespace std;
 6 int first[MAXN], next[MAXN], v[MAXN], e;
 7 int dp[MAXN][2];
 8 bool vis[MAXN];
 9 inline void addEdge(int x, int y) {
10     v[e] = y;
11     next[e] = first[x];
12     first[x] = e++;
13 }
14 void dfs(int x) {
15     vis[x] = true;
16     dp[x][0] = dp[x][1] = 0;
17     for (int i = first[x]; i != -1; i = next[i]) {
18         int y = v[i];
19         if (!vis[y]) {
20             dfs(y);
21             if (dp[y][0] + 1 >= dp[x][0]) {
22                 dp[x][1] = dp[x][0];
23                 dp[x][0] = dp[y][0] + 1;
24             } else if (dp[y][0] + 1 >= dp[x][1]) {
25                 dp[x][1] = dp[y][0] + 1;
26             }
27         }
28     }
29 }
30 int main() {
31     int T;
32     int n, m;
33     int i;
34     int x, y;
35     scanf("%d", &T);
36     while (T--) {
37         scanf("%d%d", &n, &m);
38         e = 0;
39         memset(first, -1, sizeof(first));
40         for (i = 1; i < n; i++) {
41             scanf("%d%d", &x, &y);
42             addEdge(x, y);
43             addEdge(y, x);
44         }
45         memset(vis, false, sizeof(vis));
46         dfs(1);
47         x = 0;
48         for (i = 1; i <= n; i++) {
49             x = max(x, dp[i][0] + dp[i][1]);
50         }
51         while (m--) {
52             scanf("%d", &y);
53             if (y <= x + 1) {
54                 printf("%d
", y - 1);
55             } else {
56                 printf("%d
", x + 2 * (y - x - 1));
57             }
58         }
59     }
60     return 0;
61 }
View Code

HDU 4608  I-number

因为y不会比x大多少,所以直接高精度加法暴力。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MAXN 200010
 5 using namespace std;
 6 int digit[MAXN];
 7 char str[MAXN];
 8 int main() {
 9     int T;
10     int i;
11     int len;
12     int sum;
13     scanf("%d", &T);
14     while (T--) {
15         scanf(" %s", str);
16         len = strlen(str);
17         memset(digit, 0, sizeof(digit));
18         for (i = 0; str[i]; i++) {
19             digit[i] = str[i] - '0';
20         }
21         reverse(digit, digit + len);
22         while (1) {
23             digit[0]++;
24             sum = 0;
25             for (i = 0; i < len; i++) {
26                 if (digit[i] > 9) {
27                     digit[i] -= 10;
28                     digit[i + 1]++;
29                     if (i == len - 1) {
30                         len++;
31                     }
32                 }
33                 sum += digit[i];
34             }
35             if (sum % 10 == 0) {
36                 break;
37             }
38         }
39         for (i = len - 1; i >= 0; i--) {
40             printf("%d", digit[i]);
41         }
42         putchar('
');
43     }
44     return 0;
45 }
View Code

HDU 4609 3-idiots

对于多项式乘法,普通做法需要O(n2)的时间复杂度。

而FFT仅需要O(nlogn)的时间复杂度。

把三角形边长作为多项式的指数,边长的出现次数作为多项式的系数。

把两个多项式相乘,即可得到任意两边长之和(i)出现的次数(num[i])。

由于一条边只能使用一次,所以num[arr[i]+arr[i]]--。

由于“先a后b”与“先b后a”属于同一种方案,所以num[i]>>=1。

不妨假设a<=b<=c,要构成三角形只要满足a+b>c。

由于a+b>c不容易统计,但是a+b<=c的方案数很容易统计,枚举c就可以做到。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<algorithm>
  5 #define MAXN 400010
  6 #define EPS 1e-8
  7 typedef long long LL;
  8 using namespace std;
  9 double PI = acos(-1.0);
 10 int arr[MAXN];
 11 LL num[MAXN], sum[MAXN];
 12 struct complex {
 13     double r, i;
 14     complex(double _r = 0, double _i = 0) {
 15         r = _r;
 16         i = _i;
 17     }
 18     complex operator+(const complex &b) {
 19         return complex(r + b.r, i + b.i);
 20     }
 21     complex operator-(const complex &b) {
 22         return complex(r - b.r, i - b.i);
 23     }
 24     complex operator*(const complex &b) {
 25         return complex(r * b.r - i * b.i, r * b.i + i * b.r);
 26     }
 27 };
 28 complex x[MAXN];
 29 void change(complex y[], int len) {
 30     for (int i = 1, j = len >> 1; i < len - 1; i++) {
 31         if (i < j) {
 32             swap(y[i], y[j]);
 33         }
 34         int k = len >> 1;
 35         for (; j >= k; k >>= 1) {
 36             j -= k;
 37         }
 38         if (j < k) {
 39             j += k;
 40         }
 41     }
 42 }
 43 void FFT(complex y[], int len, int on) {
 44     change(y, len);
 45     for (int h = 2; h <= len; h <<= 1) {
 46         complex wn(cos(-on * 2 * PI / h), sin(-on * 2 * PI / h));
 47         for (int j = 0; j < len; j += h) {
 48             complex w(1, 0);
 49             for (int k = j; k < j + (h >> 1); k++) {
 50                 complex u = y[k];
 51                 complex t = w * y[k + (h >> 1)];
 52                 y[k] = u + t;
 53                 y[k + (h >> 1)] = u - t;
 54                 w = w * wn;
 55             }
 56         }
 57     }
 58     if (on == -1) {
 59         for (int i = 0; i < len; i++) {
 60             y[i].r /= len;
 61         }
 62     }
 63 }
 64 int main() {
 65     int T;
 66     int n;
 67     int len, len1;
 68     double ans;
 69     scanf("%d", &T);
 70     while (T--) {
 71         memset(num, 0, sizeof(num));
 72         scanf("%d", &n);
 73         for (int i = 0; i < n; i++) {
 74             scanf("%d", &arr[i]);
 75             num[arr[i]]++;
 76         }
 77         sort(arr, arr + n);
 78         len1 = arr[n - 1] + 1;
 79         for (len = 1; len <= (len1 << 1); len <<= 1)
 80             ;
 81         for (int i = 0; i < len1; i++) {
 82             x[i] = complex(num[i], 0);
 83         }
 84         for (int i = len1; i < len; i++) {
 85             x[i] = complex(0, 0);
 86         }
 87         FFT(x, len, 1);
 88         for (int i = 0; i < len; i++) {
 89             x[i] = x[i] * x[i];
 90         }
 91         FFT(x, len, -1);
 92         for (int i = 0; i < len; i++) {
 93             num[i] = (LL) (x[i].r + 0.5 + EPS);
 94         }
 95         for (int i = 0; i < n; i++) {
 96             num[arr[i] + arr[i]]--;
 97         }
 98         for (int i = 0; i < len; i++) {
 99             num[i] >>= 1;
100         }
101         sum[0] = 0;
102         for (int i = 1; i < len; i++) {
103             sum[i] = sum[i - 1] + num[i];
104         }
105         ans = 0;
106         for (int i = 0; i < n; i++) {
107             ans += sum[arr[i]];
108         }
109         printf("%.7lf
", 1 - ans * 6 / (n * (n - 1.0) * (n - 2.0)));
110     }
111     return 0;
112 }
View Code

4610 Cards

通过筛素数可以快速判定素数。

条件1,条件2可以快速解决;

条件3,一个数约数之和可能大于该数的好几倍;

条件4,一个数约束的乘积可能爆longlong,要通过分解素因子,判是否是平方数。

由于N的总数不超过20000,N个数的范围都在106内,所以可以O(sqrt(n))的复杂度处理出约数。

由于条件只有4个,所以K个数中,只有24=16个不同种类的数。因此可以枚举每种数是否出现216,贪心的选择。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<algorithm>
  5 #include<map>
  6 #define oo 987654321
  7 #define MAXP 5000010
  8 #define MAXN 1000010
  9 #define MAXM 4
 10 typedef long long LL;
 11 using namespace std;
 12 bool p[MAXP];
 13 int num[1 << MAXM];
 14 int satisfy[MAXN];
 15 int add[MAXM];
 16 vector<int> prime;
 17 void init() {
 18     int i, j;
 19     memset(p, true, sizeof(p));
 20     p[0] = p[1] = false;
 21     for (i = 2; i * i < MAXP; i++) {
 22         if (p[i]) {
 23             for (j = i * i; j < MAXP; j += i) {
 24                 p[j] = false;
 25             }
 26         }
 27     }
 28     for (i = 2; i < MAXP; i++) {
 29         if (p[i]) {
 30             prime.push_back(i);
 31         }
 32     }
 33 }
 34 bool isSquare(int val, int cnt, int flag) {
 35     map<int, int> mymap;
 36     int i;
 37     for (i = 0; prime[i] * prime[i] <= val; i++) {
 38         while (val % prime[i] == 0) {
 39             mymap[prime[i]]++;
 40             val /= prime[i];
 41         }
 42     }
 43     if (val > 1) {
 44         mymap[val]++;
 45     }
 46     map<int, int>::iterator it;
 47     for (it = mymap.begin(); it != mymap.end(); it++) {
 48         (*it).second *= cnt;
 49     }
 50     for (i = 0; prime[i] * prime[i] <= flag; i++) {
 51         while (flag % prime[i] == 0) {
 52             mymap[prime[i]]++;
 53             flag /= prime[i];
 54         }
 55     }
 56     if (flag > 1) {
 57         mymap[flag]++;
 58     }
 59     for (it = mymap.begin(); it != mymap.end(); it++) {
 60         if ((*it).second & 1) {
 61             return false;
 62         }
 63     }
 64     return true;
 65 }
 66 void getSatisfy(int val) {
 67     if (satisfy[val] < 0) {
 68         int res = 0;
 69         int i;
 70         int amount = 0;
 71         int sum = 0;
 72         int product = 0;
 73         int flag = 1;
 74         for (i = 1; i * i < val; i++) {
 75             if (val % i == 0) {
 76                 amount += 2;
 77                 sum += i + val / i;
 78                 product++;
 79             }
 80         }
 81         if (i * i == val) {
 82             amount++;
 83             sum += i;
 84             flag = i;
 85         }
 86         if (p[val]) {
 87             res |= 1 << 0;
 88         }
 89         if (p[amount]) {
 90             res |= 1 << 1;
 91         }
 92         if (p[sum]) {
 93             res |= 1 << 2;
 94         }
 95         if (isSquare(val, product, flag)) {
 96             res |= 1 << 3;
 97         }
 98         satisfy[val] = res;
 99     }
100 }
101 int numOfOne(int val) {
102     int res;
103     for (res = 0; val; val >>= 1) {
104         res += val & 1;
105     }
106     return res;
107 }
108 bool cmp(int x, int y) {
109     return numOfOne(x) > numOfOne(y);
110 }
111 int main() {
112     int T;
113     int n, k;
114     int i, j;
115     int tmp, cnt;
116     int ans, res;
117     int sum;
118     bool flag;
119     vector<int> g;
120     init();
121     memset(satisfy, -1, sizeof(satisfy));
122     scanf("%d", &T);
123     while (T--) {
124         memset(num, 0, sizeof(num));
125         scanf("%d%d", &n, &k);
126         for (i = 0; i < n; i++) {
127             scanf("%d%d", &tmp, &cnt);
128             getSatisfy(tmp);
129             num[satisfy[tmp]] += cnt;
130 
131             printf("%d", numOfOne(satisfy[tmp]));
132             if (i < n - 1) {
133                 putchar(' ');
134             } else {
135                 putchar('
');
136             }
137         }
138         for (i = 0; i < MAXM; i++) {
139             scanf("%d", &add[i]);
140         }
141         ans = -oo;
142         for (i = 0; i < (1 << (1 << MAXM)); i++) {
143             g.clear();
144             for (tmp = i, j = 0; tmp; tmp >>= 1, j++) {
145                 if (tmp & 1) {
146                     g.push_back(j);
147                 }
148             }
149             if ((int) g.size() > k) {
150                 continue;
151             }
152             flag = true;
153             sum = 0;
154             tmp = 0;
155             for (j = 0; flag && j < (int) g.size(); j++) {
156                 if (num[g[j]] <= 0) {
157                     flag = false;
158                 }
159                 sum += num[g[j]];
160                 tmp |= g[j];
161             }
162             if (flag && sum >= k) {
163                 sort(g.begin(), g.end(), cmp);
164                 res = 0;
165                 for (j = 0; j < MAXM; j++, tmp >>= 1) {
166                     if (!(tmp & 1)) {
167                         res += add[j];
168                     }
169                 }
170                 for (j = 0; j < (int) g.size(); j++) {
171                     res += numOfOne(g[j]);
172                 }
173                 tmp = k - g.size();
174                 for (j = 0; tmp && j < (int) g.size(); j++) {
175                     cnt = min(tmp, num[g[j]] - 1);
176                     res += cnt * numOfOne(g[j]);
177                     tmp -= cnt;
178                 }
179                 ans = max(ans, res);
180             }
181         }
182         printf("%d
", ans);
183     }
184     return 0;
185 }
View Code
原文地址:https://www.cnblogs.com/DrunBee/p/3209212.html