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 }
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\n", ans); 50 } 51 return 0; 52 }
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\n", res[i].first, res[i].second); 127 } 128 } 129 } 130 return 0; 131 }
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\n", mid); 265 266 } 267 return 0; 268 }
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\n", y - 1); 55 } else { 56 printf("%d\n", x + 2 * (y - x - 1)); 57 } 58 } 59 } 60 return 0; 61 }
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('\n'); 43 } 44 return 0; 45 }
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\n", 1 - ans * 6 / (n * (n - 1.0) * (n - 2.0))); 110 } 111 return 0; 112 }
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('\n'); 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\n", ans); 183 } 184 return 0; 185 }