HDU 4611 Balls Rearrangement
令lcm=LCM(a,b),gcd=GCD(a,b)。cal(n,a,b)表示sum(abs(i%a-i%b)),0<=i<n。
显然,答案就是cal(lcm,a,b)*(n/lcm)+cal(n%lcm,a,b)。
cal(n,a,b)可以通过暴力得到,即对i%a和i%b的值分段,连续的一段(遇到0终止)可以直接得到值。
因此,每段的长度将直接影响到时间复杂度。
当lcm较小时,cal中的n不会很大,即使每段长度很小也无所谓。
当lcm较大时,每段的长度会比较大。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 typedef long long LL; 4 using namespace std; 5 LL GCD(LL x, LL y) { 6 return y ? GCD(y, x % y) : x; 7 } 8 LL LCM(LL x, LL y) { 9 return x / GCD(x, y) * y; 10 } 11 LL cal(LL n, LL a, LL b) { 12 LL ans = 0; 13 LL x, y, tmp; 14 x = 0; 15 y = a; 16 for (LL i = a; i < n;) { 17 tmp = min(a - x, b - y); 18 if (i + tmp > n) { 19 tmp = n - i; 20 } 21 i += tmp; 22 ans += tmp * abs(x - y); 23 x = (x + tmp) % a; 24 y = (y + tmp) % b; 25 } 26 return ans; 27 } 28 int main() { 29 int T; 30 LL n, a, b; 31 LL lcm; 32 LL ans; 33 cin >> T; 34 while (T--) { 35 cin >> n >> a >> b; 36 if (a == b) { 37 ans = 0; 38 } else { 39 if (a > b) { 40 swap(a, b); 41 } 42 lcm = LCM(a, b); 43 ans = (n / lcm) * cal(lcm, a, b) + cal(n % lcm, a, b); 44 } 45 cout << ans << endl; 46 } 47 return 0; 48 }
HDU 4612 Warm up
把桥处理出来,对双连通分量缩点,得到一棵树。
求树上最长链,将最长链的两端连起来,剩下的桥的个数就是答案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #pragma comment(linker,"/STACK:102400000,102400000") 2 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define MAXN 200010 7 #define MAXM 2000010 8 using namespace std; 9 int first[MAXN], next[MAXM], v[MAXM], e; 10 int dfn[MAXN], low[MAXN]; 11 int belong[MAXN]; 12 bool vis[MAXN]; 13 int n, m; 14 int dp[MAXN][2]; 15 int father[MAXN]; 16 struct Edge { 17 int x, y; 18 }; 19 Edge g[MAXM]; 20 Edge tree[MAXM]; 21 inline void addEdge(int x, int y) { 22 v[e] = y; 23 next[e] = first[x]; 24 first[x] = e++; 25 } 26 void makeSet(int n) { 27 for (int i = 0; i <= n; i++) { 28 father[i] = i; 29 } 30 } 31 int findSet(int x) { 32 if (father[x] != x) { 33 father[x] = findSet(father[x]); 34 } 35 return father[x]; 36 } 37 void myUnion(int x, int y) { 38 x = findSet(x); 39 y = findSet(y); 40 if (x != y) { 41 father[x] = y; 42 } 43 } 44 void dfs(int x, int index, int depth) { 45 dfn[x] = low[x] = depth; 46 for (int i = first[x]; i != -1; i = next[i]) { 47 if ((i ^ 1) == index) { 48 continue; 49 } 50 int y = v[i]; 51 if (dfn[y]) { 52 low[x] = min(low[x], dfn[y]); 53 } else { 54 dfs(y, i, depth + 1); 55 low[x] = min(low[x], low[y]); 56 if (low[y] > dfn[x]) { 57 tree[m].x = x; 58 tree[m++].y = y; 59 } else { 60 myUnion(x, y); 61 } 62 } 63 } 64 } 65 void search(int x) { 66 vis[x] = true; 67 for (int i = first[x]; i != -1; i = next[i]) { 68 int y = v[i]; 69 if (!vis[y]) { 70 search(y); 71 if (dp[y][0] + 1 >= dp[x][0]) { 72 dp[x][1] = dp[x][0]; 73 dp[x][0] = dp[y][0] + 1; 74 } else if (dp[y][0] + 1 > dp[x][1]) { 75 dp[x][1] = dp[y][0] + 1; 76 } 77 } 78 } 79 } 80 int main() { 81 int i; 82 int ans; 83 int cnt; 84 while (scanf("%d%d", &n, &m), n) { 85 e = 0; 86 memset(first, -1, sizeof(first)); 87 for (i = 0; i < m; i++) { 88 scanf("%d%d", &g[i].x, &g[i].y); 89 addEdge(g[i].x, g[i].y); 90 addEdge(g[i].y, g[i].x); 91 } 92 makeSet(n); 93 m = 0; 94 memset(dfn, 0, sizeof(dfn)); 95 dfs(1, -1, 1); 96 memset(belong, -1, sizeof(belong)); 97 cnt = 0; 98 for (i = 1; i <= n; i++) { 99 if (belong[findSet(i)] == -1) { 100 belong[findSet(i)] = ++cnt; 101 } 102 belong[i] = belong[findSet(i)]; 103 } 104 e = 0; 105 memset(first, -1, sizeof(first)); 106 for (i = 0; i < m; i++) { 107 addEdge(belong[tree[i].x], belong[tree[i].y]); 108 addEdge(belong[tree[i].y], belong[tree[i].x]); 109 } 110 if (m == 0) { 111 ans = 0; 112 } else { 113 memset(dp, 0, sizeof(dp)); 114 memset(vis, false, sizeof(vis)); 115 search(belong[tree[0].x]); 116 ans = 0; 117 for (i = 1; i <= cnt; i++) { 118 ans = max(ans, dp[i][0] + dp[i][1]); 119 } 120 ans = m - ans; 121 } 122 printf("%d\n", ans); 123 } 124 return 0; 125 }
HDU 4614 Vases and Flowers
K=1,二分得到起点和终点,区间覆盖为1。
K=2,区间求和,区间覆盖为0。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define MAXN 50010 6 struct node { 7 int lazy; 8 int sum; 9 } tree[MAXN << 2]; 10 inline void pushUp(int rt) { 11 tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum; 12 } 13 void build(int L, int R, int rt) { 14 tree[rt].lazy = -1; 15 tree[rt].sum = 0; 16 if (L != R) { 17 int mid = (L + R) >> 1; 18 build(L, mid, rt << 1); 19 build(mid + 1, R, rt << 1 | 1); 20 } 21 } 22 inline void pushDown(int mid, int L, int R, int rt) { 23 if (tree[rt].lazy != -1) { 24 tree[rt << 1].lazy = tree[rt << 1 | 1].lazy = tree[rt].lazy; 25 tree[rt << 1].sum = tree[rt].lazy * (mid - L + 1); 26 tree[rt << 1 | 1].sum = tree[rt].lazy * (R - mid); 27 tree[rt].lazy = -1; 28 } 29 } 30 int sum(int x, int y, int L, int R, int rt) { 31 if (x <= L && R <= y) { 32 return tree[rt].sum; 33 } else { 34 int mid = (L + R) >> 1; 35 pushDown(mid, L, R, rt); 36 int ans = 0; 37 if (x <= mid) { 38 ans += sum(x, y, L, mid, rt << 1); 39 } 40 if (y > mid) { 41 ans += sum(x, y, mid + 1, R, rt << 1 | 1); 42 } 43 pushUp(rt); 44 return ans; 45 } 46 } 47 void cover(int x, int y, int val, int L, int R, int rt) { 48 if (x <= L && R <= y) { 49 tree[rt].lazy = val; 50 tree[rt].sum = (R - L + 1) * val; 51 } else { 52 int mid = (L + R) >> 1; 53 pushDown(mid, L, R, rt); 54 if (x <= mid) { 55 cover(x, y, val, L, mid, rt << 1); 56 } 57 if (y > mid) { 58 cover(x, y, val, mid + 1, R, rt << 1 | 1); 59 } 60 pushUp(rt); 61 } 62 } 63 int main() { 64 int T; 65 int n, m; 66 int k, a, b; 67 int x, y; 68 int low, high, mid; 69 int tot; 70 scanf("%d", &T); 71 while (T--) { 72 scanf("%d%d", &n, &m); 73 build(0, n - 1, 1); 74 while (m--) { 75 scanf("%d%d%d", &k, &a, &b); 76 if (k == 1) { 77 tot = n - a - sum(a, n - 1, 0, n - 1, 1); 78 tot = min(tot, b); 79 if (tot == 0) { 80 puts("Can not put any one."); 81 } else { 82 low = a; 83 high = n; 84 while (low < high) { 85 mid = (low + high) >> 1; 86 if (mid - a + 1 - sum(a, mid, 0, n - 1, 1) >= 1) { 87 high = mid; 88 x = mid; 89 } else { 90 low = mid + 1; 91 } 92 } 93 low = a; 94 high = n; 95 while (low < high) { 96 mid = (low + high) >> 1; 97 if (mid - a + 1 - sum(a, mid, 0, n - 1, 1) >= tot) { 98 high = mid; 99 y = mid; 100 } else { 101 low = mid + 1; 102 } 103 } 104 printf("%d %d\n", x, y); 105 cover(x, y, 1, 0, n - 1, 1); 106 } 107 } else { 108 printf("%d\n", sum(a, b, 0, n - 1, 1)); 109 cover(a, b, 0, 0, n - 1, 1); 110 } 111 } 112 putchar('\n'); 113 } 114 return 0; 115 }
HDU 4616 Game
up[i][j][0]表示从下往上走,经历j个障碍的最大收益。
up[i][j][1]表示从下往上走,经历j个障碍的次大收益。
down[i][j][0]表示从上往下走,经历j个障碍的最大收益。
down[i][j][1]表示从上往下走,经历j个障碍的次大收益。
答案可能由up[i][j][0]+up[i][j][1]-val[i],up[i][j][0]+down[i][j][0]-val[i],up[i][j][1]+down[i][j][0]-val[i],up[i][j][0]+down[i][j][1]-val[i]得到。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAXN 100010 5 #define MAXM 4 6 #define oo 987654321 7 using namespace std; 8 bool vis[MAXN]; 9 int first[MAXN], next[MAXN], v[MAXN], e; 10 int n, m; 11 int val[MAXN], trap[MAXN]; 12 int up[MAXN][MAXM][2], fromUp[MAXN][MAXM][2]; 13 int down[MAXN][MAXM][2], fromDown[MAXN][MAXM][2]; 14 inline void addEdge(int x, int y) { 15 v[e] = y; 16 next[e] = first[x]; 17 first[x] = e++; 18 } 19 void dfs(int x) { 20 vis[x] = true; 21 for (int i = 0; i <= m; i++) { 22 for (int j = 0; j < 2; j++) { 23 up[x][i][j] = down[x][i][j] = -oo; 24 } 25 } 26 up[x][trap[x]][0] = val[x]; 27 if (trap[x]) { 28 down[x][trap[x]][0] = val[x]; 29 } 30 for (int i = first[x]; i != -1; i = next[i]) { 31 int y = v[i]; 32 if (!vis[y]) { 33 dfs(y); 34 for (int j = trap[x]; j <= m; j++) { 35 if (up[x][j][0] <= up[y][j - trap[x]][0] + val[x]) { 36 up[x][j][1] = up[x][j][0]; 37 fromUp[x][j][1] = fromUp[x][j][0]; 38 up[x][j][0] = up[y][j - trap[x]][0] + val[x]; 39 fromUp[x][j][0] = y; 40 } else if (up[x][j][1] < up[y][j - trap[x]][0] + val[x]) { 41 up[x][j][1] = up[y][j - trap[x]][0] + val[x]; 42 fromUp[x][j][1] = y; 43 } 44 if (down[x][j][0] <= down[y][j - trap[x]][0] + val[x]) { 45 down[x][j][1] = down[x][j][0]; 46 fromDown[x][j][1] = fromDown[x][j][0]; 47 down[x][j][0] = down[y][j - trap[x]][0] + val[x]; 48 fromDown[x][j][0] = y; 49 } else if (down[x][j][1] < down[y][j - trap[x]][0] + val[x]) { 50 down[x][j][1] = down[y][j - trap[x]][0] + val[x]; 51 fromDown[x][j][1] = y; 52 } 53 } 54 } 55 } 56 } 57 int main() { 58 int T; 59 int i, j, k; 60 int x, y; 61 int ans; 62 scanf("%d", &T); 63 while (T--) { 64 scanf("%d%d", &n, &m); 65 for (i = 0; i < n; i++) { 66 scanf("%d%d", &val[i], &trap[i]); 67 } 68 e = 0; 69 memset(first, -1, sizeof(first)); 70 for (i = 1; i < n; i++) { 71 scanf("%d%d", &x, &y); 72 addEdge(x, y); 73 addEdge(y, x); 74 } 75 memset(vis, false, sizeof(vis)); 76 dfs(0); 77 ans = -oo; 78 for (i = 0; i < n; i++) { 79 for (j = 0; j <= m; j++) { 80 if (j < m) { 81 ans = max(ans, up[i][j][0]); 82 } 83 for (k = 0; k + j <= m; k++) { 84 if (fromUp[i][j][0] != fromDown[i][k][0]) { 85 ans = max(ans, up[i][j][0] + down[i][k][0] - val[i]); 86 } else { 87 ans = max(ans, up[i][j][0] + down[i][k][1] - val[i]); 88 ans = max(ans, up[i][j][1] + down[i][k][0] - val[i]); 89 } 90 if (k + j < m) { 91 ans = max(ans, up[i][j][0] + up[i][k][1] - val[i]); 92 } 93 } 94 } 95 } 96 printf("%d\n", ans); 97 } 98 return 0; 99 }
HDU 4617 Weapon
对给定的平面求法向量,结合圆心,得到直线。
求空间直线的距离,若直线i与直线j的最短距离<=半径i+半径j,则相交;否则,答案就是任意两条直线距离的最小值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #define eps 1e-8 5 #define oo 1e50 6 #define MAXN 55 7 using namespace std; 8 struct point3 { 9 double x, y, z; 10 }; 11 struct line3 { 12 point3 a, b; 13 }; 14 struct plane3 { 15 point3 a, b, c; 16 }; 17 double r[MAXN]; 18 double dis[MAXN][MAXN]; 19 plane3 p[MAXN]; 20 line3 l[MAXN]; 21 double dist(point3 p1, point3 p2) { 22 return sqrt( 23 (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) 24 + (p1.z - p2.z) * (p1.z - p2.z)); 25 } 26 point3 xmult(point3 u, point3 v) { 27 point3 ret; 28 ret.x = u.y * v.z - v.y * u.z; 29 ret.y = u.z * v.x - u.x * v.z; 30 ret.z = u.x * v.y - u.y * v.x; 31 return ret; 32 } 33 point3 subt(point3 u, point3 v) { 34 point3 ret; 35 ret.x = u.x - v.x; 36 ret.y = u.y - v.y; 37 ret.z = u.z - v.z; 38 return ret; 39 } 40 point3 add(point3 u, point3 v) { 41 point3 ret; 42 ret.x = u.x + v.x; 43 ret.y = u.y + v.y; 44 ret.z = u.z + v.z; 45 return ret; 46 } 47 point3 pvec(plane3 s) { 48 return xmult(subt(s.a, s.b), subt(s.b, s.c)); 49 } 50 double dmult(point3 u, point3 v) { 51 return u.x * v.x + u.y * v.y + u.z * v.z; 52 } 53 double vlen(point3 p) { 54 return sqrt(p.x * p.x + p.y * p.y + p.z * p.z); 55 } 56 double linetoline(line3 u, line3 v) { 57 point3 n = xmult(subt(u.a, u.b), subt(v.a, v.b)); 58 return fabs(dmult(subt(u.a, v.a), n)) / vlen(n); 59 } 60 int dbcmp(double x, double y) { 61 if (fabs(x - y) < eps) { 62 return 0; 63 } else { 64 return x > y ? 1 : -1; 65 } 66 } 67 int main() { 68 int T; 69 int n; 70 int i, j; 71 point3 tmp; 72 bool flag; 73 double ans; 74 scanf("%d", &T); 75 while (T--) { 76 scanf("%d", &n); 77 for (i = 0; i < n; i++) { 78 scanf("%lf%lf%lf", &p[i].a.x, &p[i].a.y, &p[i].a.z); 79 scanf("%lf%lf%lf", &p[i].b.x, &p[i].b.y, &p[i].b.z); 80 scanf("%lf%lf%lf", &p[i].c.x, &p[i].c.y, &p[i].c.z); 81 r[i] = dist(p[i].a, p[i].b); 82 tmp = pvec(p[i]); 83 l[i].a = p[i].a; 84 l[i].b = add(l[i].a, tmp); 85 } 86 flag = false; 87 for (i = 0; i < n; i++) { 88 dis[i][i] = 0; 89 for (j = i + 1; j < n; j++) { 90 dis[i][j] = dis[j][i] = linetoline(l[i], l[j]); 91 } 92 } 93 ans = oo; 94 for (i = 0; i < n; i++) { 95 for (j = i + 1; j < n; j++) { 96 if (dbcmp(dis[i][j], r[i] + r[j]) <= 0) { 97 flag = true; 98 } else { 99 ans = min(ans, dis[i][j] - r[i] - r[j]); 100 } 101 } 102 } 103 if (flag) { 104 puts("Lucky"); 105 } else { 106 printf("%.2lf\n", ans); 107 } 108 } 109 return 0; 110 }
4618 Palindrome Sub-Array
回文串要分奇偶考虑。
分别枚举横,竖的数组,并枚举回文串的中间位置,二分哈希值求出最长回文串。
枚举横,竖数组的中间位置,二分答案。
复杂度O(n3log2n),常数比较小。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAXN 310 5 #define SEED 100000007 6 typedef unsigned long long LL; 7 using namespace std; 8 int n, m; 9 int ans; 10 int arr[MAXN][MAXN]; 11 LL seed[MAXN]; 12 LL hl[MAXN], hr[MAXN]; 13 int r[MAXN][MAXN]; 14 int c[MAXN][MAXN]; 15 void init() { 16 seed[0] = 1; 17 for (int i = 1; i < MAXN; i++) { 18 seed[i] = seed[i - 1] * SEED; 19 } 20 } 21 void hash(int tmp[], int size) { 22 int i; 23 hl[0] = tmp[0]; 24 for (i = 1; i < size; i++) { 25 hl[i] = seed[i] * tmp[i] + hl[i - 1]; 26 } 27 hr[size - 1] = tmp[size - 1]; 28 for (i = size - 2; i >= 0; i--) { 29 hr[i] = seed[size - i - 1] * tmp[i] + hr[i + 1]; 30 } 31 } 32 bool isOK(int x0, int y0, int x1, int y1, int size) { 33 if (x0 <= y0 && x1 <= y1) { 34 LL a = hl[y0]; 35 if (x0 - 1 >= 0) { 36 a -= hl[x0 - 1]; 37 } 38 LL b = hr[x1]; 39 if (y1 + 1 < size) { 40 b -= hr[y1 + 1]; 41 } 42 if (x0 > size - 1 - y1) { 43 b *= seed[x0 - (size - 1 - y1)]; 44 } else { 45 a *= seed[size - 1 - y1 - x0]; 46 } 47 return a == b; 48 } else { 49 return false; 50 } 51 } 52 bool isOddGood(int x, int y, int len) { 53 int i; 54 for (i = x - 1; i >= x - len; i--) { 55 if (r[i][y] < len) { 56 return false; 57 } 58 } 59 for (i = x + 1; i <= x + len; i++) { 60 if (r[i][y] < len) { 61 return false; 62 } 63 } 64 for (i = y - 1; i >= y - len; i--) { 65 if (c[x][i] < len) { 66 return false; 67 } 68 } 69 for (i = y + 1; i <= y + len; i++) { 70 if (c[x][i] < len) { 71 return false; 72 } 73 } 74 return true; 75 } 76 void odd() { 77 int i, j; 78 int tmp[MAXN]; 79 int low, high, mid, res; 80 memset(r, 0, sizeof(r)); 81 for (i = 0; i < n; i++) { 82 for (j = 0; j < m; j++) { 83 tmp[j] = arr[i][j]; 84 } 85 hash(tmp, m); 86 for (j = 1; j < m - 1; j++) { 87 res = 0; 88 low = 0; 89 high = min(j, m - 1 - j) + 1; 90 while (low < high) { 91 mid = (low + high) >> 1; 92 if (isOK(j - mid, j - 1, j + 1, j + mid, m)) { 93 res = mid; 94 low = mid + 1; 95 } else { 96 high = mid; 97 } 98 } 99 r[i][j] = res; 100 } 101 } 102 memset(c, 0, sizeof(c)); 103 for (i = 0; i < m; i++) { 104 for (j = 0; j < n; j++) { 105 tmp[j] = arr[j][i]; 106 } 107 hash(tmp, n); 108 for (j = 1; j < n - 1; j++) { 109 res = 0; 110 low = 0; 111 high = min(j, n - 1 - j) + 1; 112 while (low < high) { 113 mid = (low + high) >> 1; 114 if (isOK(j - mid, j - 1, j + 1, j + mid, n)) { 115 res = mid; 116 low = mid + 1; 117 } else { 118 high = mid; 119 } 120 } 121 c[j][i] = res; 122 } 123 } 124 for (i = 0; i < n; i++) { 125 for (j = 0; j < m; j++) { 126 if (r[i][j] && c[i][j]) { 127 res = 0; 128 low = 0; 129 high = min(r[i][j], c[i][j]) + 1; 130 while (low < high) { 131 mid = (low + high) >> 1; 132 if (isOddGood(i, j, mid)) { 133 low = mid + 1; 134 res = mid; 135 } else { 136 high = mid; 137 } 138 } 139 ans = max(ans, res << 1 | 1); 140 } 141 } 142 } 143 } 144 bool isEvenGood(int x, int y, int len) { 145 int i; 146 for (i = x - 1; i > x - len; i--) { 147 if (r[i][y] < len) { 148 return false; 149 } 150 } 151 for (i = x + 1; i <= x + len; i++) { 152 if (r[i][y] < len) { 153 return false; 154 } 155 } 156 for (i = y - 1; i > y - len; i--) { 157 if (c[x][i] < len) { 158 return false; 159 } 160 } 161 for (i = y + 1; i <= y + len; i++) { 162 if (c[x][i] < len) { 163 return false; 164 } 165 } 166 return true; 167 } 168 void even() { 169 int i, j; 170 int tmp[MAXN]; 171 int low, high, mid, res; 172 memset(r, 0, sizeof(r)); 173 for (i = 0; i < n; i++) { 174 for (j = 0; j < m; j++) { 175 tmp[j] = arr[i][j]; 176 } 177 hash(tmp, m); 178 for (j = 1; j < m - 1; j++) { 179 res = 0; 180 low = 0; 181 high = min(j + 1, m - 1 - j) + 1; 182 while (low < high) { 183 mid = (low + high) >> 1; 184 if (isOK(j - mid + 1, j, j + 1, j + mid, m)) { 185 res = mid; 186 low = mid + 1; 187 } else { 188 high = mid; 189 } 190 } 191 r[i][j] = res; 192 } 193 } 194 memset(c, 0, sizeof(c)); 195 for (i = 0; i < m; i++) { 196 for (j = 0; j < n; j++) { 197 tmp[j] = arr[j][i]; 198 } 199 hash(tmp, n); 200 for (j = 1; j < n - 1; j++) { 201 res = 0; 202 low = 0; 203 high = min(j + 1, n - 1 - j) + 1; 204 while (low < high) { 205 mid = (low + high) >> 1; 206 if (isOK(j - mid + 1, j, j + 1, j + mid, n)) { 207 res = mid; 208 low = mid + 1; 209 } else { 210 high = mid; 211 } 212 } 213 c[j][i] = res; 214 } 215 } 216 for (i = 0; i < n; i++) { 217 for (j = 0; j < m; j++) { 218 if (r[i][j] && c[i][j]) { 219 res = 0; 220 low = 0; 221 high = min(r[i][j], c[i][j]) + 1; 222 while (low < high) { 223 mid = (low + high) >> 1; 224 if (isEvenGood(i, j, mid)) { 225 low = mid + 1; 226 res = mid; 227 } else { 228 high = mid; 229 } 230 } 231 ans = max(ans, res << 1); 232 } 233 } 234 } 235 } 236 int main() { 237 int T; 238 int i, j; 239 init(); 240 scanf("%d", &T); 241 while (T--) { 242 scanf("%d%d", &n, &m); 243 for (i = 0; i < n; i++) { 244 for (j = 0; j < m; j++) { 245 scanf("%d", &arr[i][j]); 246 } 247 } 248 ans = 1; 249 odd(); 250 even(); 251 printf("%d\n", ans); 252 } 253 return 0; 254 }
HDU 4619 Warm up 2
有冲突的两个骨牌连边,求最大匹配。
最大独立集=顶点数-最大匹配。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #pragma comment(linker,"/STACK:102400000,102400000") 2 3 #include<cstdio> 4 #include<cstring> 5 #include<vector> 6 #define MAXN 100010 7 #define MAXM 1000010 8 #define oo 123456789 9 using namespace std; 10 int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e; 11 int n, m; 12 int src, des; 13 inline void addEdge(int x, int y, int val) { 14 v[e] = y; 15 cost[e] = val; 16 next[e] = first[x]; 17 first[x] = e++; 18 19 v[e] = x; 20 cost[e] = 0; 21 next[e] = first[y]; 22 first[y] = e++; 23 } 24 int SAP() { 25 int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN]; 26 int flow = 0; 27 int aug = oo; 28 int x, y; 29 bool flag; 30 for (int i = 0; i < n; i++) { 31 cur[i] = first[i]; 32 gap[i] = dis[i] = 0; 33 } 34 gap[src] = n; 35 x = pre[src] = src; 36 while (dis[src] < n) { 37 flag = false; 38 for (int &j = cur[x]; j != -1; j = next[j]) { 39 y = v[j]; 40 if (cost[j] > 0 && dis[x] == dis[y] + 1) { 41 flag = true; 42 aug = min(aug, cost[j]); 43 pre[y] = x; 44 x = y; 45 if (x == des) { 46 flow += aug; 47 while (x != src) { 48 x = pre[x]; 49 cost[cur[x]] -= aug; 50 cost[cur[x] ^ 1] += aug; 51 } 52 aug = oo; 53 } 54 break; 55 } 56 } 57 if (flag) { 58 continue; 59 } 60 int tmp = n; 61 for (int j = first[x]; j != -1; j = next[j]) { 62 y = v[j]; 63 if (cost[j] > 0 && dis[y] < tmp) { 64 tmp = dis[y]; 65 cur[x] = j; 66 } 67 } 68 if ((--gap[dis[x]]) == 0) { 69 break; 70 } 71 gap[dis[x] = tmp + 1]++; 72 x = pre[x]; 73 } 74 return flow; 75 } 76 struct Point { 77 int x, y; 78 }; 79 struct Line { 80 Point a, b; 81 }; 82 Line p[MAXN], q[MAXN]; 83 bool equal(Point s, Point t) { 84 return s.x == t.x && s.y == t.y; 85 } 86 int main() { 87 int i, j; 88 int ans; 89 while (scanf("%d%d", &n, &m), n) { 90 e = 0; 91 memset(first, -1, sizeof(first)); 92 src = n + m; 93 des = src + 1; 94 for (i = 0; i < n; i++) { 95 scanf("%d%d", &p[i].a.x, &p[i].a.y); 96 p[i].b = p[i].a; 97 p[i].b.x++; 98 addEdge(src, i, 1); 99 } 100 for (i = 0; i < m; i++) { 101 scanf("%d%d", &q[i].a.x, &q[i].a.y); 102 q[i].b = q[i].a; 103 q[i].b.y++; 104 addEdge(n + i, des, 1); 105 } 106 for (i = 0; i < n; i++) { 107 for (j = 0; j < m; j++) { 108 if (equal(p[i].a, q[j].a) || equal(p[i].a, q[j].b) 109 || equal(p[i].b, q[j].a) || equal(p[i].b, q[j].b)) { 110 addEdge(i, n + j, 1); 111 } 112 } 113 } 114 ans = n + m; 115 n = des + 1; 116 ans -= SAP(); 117 printf("%d\n", ans); 118 } 119 return 0; 120 }
4620 Fruit Ninja Extreme
题目要求对于有奖励的切法,时间间隔不超过w,求有奖励切法的最大次数。
如果一个切法得不到奖励,那么应该选择不切。
考虑用搜索解决,没有剪枝的情况下,时间复杂度为230。
假设当前在cur,把cur之后的所有切法都假设是最优的,却无法更新答案,那么就没有必要再搜下去了。
这样可以把时间复杂度降低到可以接受的范围内。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAXN 210 5 using namespace std; 6 int n, m, w; 7 bool vis[MAXN]; 8 struct node { 9 int time; 10 int fruit[MAXN]; 11 int cnt; 12 int pos; 13 friend bool operator<(node a, node b) { 14 return a.time < b.time; 15 } 16 } arr[MAXN]; 17 int tmp[MAXN], tmpSize; 18 int ans[MAXN], ansSize; 19 void dfs(int cur, int pre, int left) { 20 if (tmpSize > ansSize) { 21 ansSize = tmpSize; 22 for (int i = 0; i < tmpSize; i++) { 23 ans[i] = tmp[i]; 24 } 25 } 26 if (left < 3) { 27 return; 28 } 29 if (cur >= n) { 30 return; 31 } 32 if (n - cur + tmpSize <= ansSize) { 33 return; 34 } 35 int cut[MAXN], cutSize; 36 for (int i = cur; i < n; i++) { 37 if (pre != -1 && arr[i].time - arr[pre].time > w) { 38 break; 39 } 40 cutSize = 0; 41 for (int j = 0; j < arr[i].cnt; j++) { 42 if (!vis[arr[i].fruit[j]]) { 43 cut[cutSize++] = arr[i].fruit[j]; 44 } 45 } 46 if (cutSize < 3) { 47 continue; 48 } 49 for (int j = 0; j < cutSize; j++) { 50 vis[cut[j]] = true; 51 } 52 tmp[tmpSize++] = arr[i].pos; 53 dfs(i + 1, i, left - cutSize); 54 tmpSize--; 55 for (int j = 0; j < cutSize; j++) { 56 vis[cut[j]] = false; 57 } 58 } 59 } 60 int main() { 61 int T; 62 int i, j; 63 scanf("%d", &T); 64 while (T--) { 65 scanf("%d%d%d", &n, &m, &w); 66 for (i = 0; i < n; i++) { 67 scanf("%d%d", &arr[i].cnt, &arr[i].time); 68 for (j = 0; j < arr[i].cnt; j++) { 69 scanf("%d", &arr[i].fruit[j]); 70 } 71 arr[i].pos = i + 1; 72 } 73 sort(arr, arr + n); 74 memset(vis, false, sizeof(vis)); 75 tmpSize = 0; 76 ansSize = 0; 77 dfs(0, -1, m); 78 printf("%d\n", ansSize); 79 sort(ans, ans + ansSize); 80 for (i = 0; i < ansSize; i++) { 81 printf("%d", ans[i]); 82 if (i < ansSize - 1) { 83 putchar(' '); 84 } else { 85 putchar('\n'); 86 } 87 } 88 } 89 return 0; 90 }