2012 Multi-University Training Contest 7
A.As long as Binbin loves Sangsang
题意:在连续的n秒中,每秒会出现m个龙珠。已知初始位置,每从一个位置i,移动到另一个位置j的时候,消耗的代价为abs(i-j), 知道了每次出现的龙珠的位置及取它的代价,每一秒必须取一颗龙珠。问 n 秒之后花费的最小代价是多少。
SOL:用dp[i][j]表示i秒之后,留在第j个龙珠所在位置的最小花费,这样就有了一个$O(n*m^2)$的做法,之后很容易想到用单调队列优化,复杂度$O(n*m)$。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 const int oo = 1e9; 8 int i, j, k, n, m, s, t, ans, x; 9 struct node { 10 int pos, cost; 11 } a[55][1005]; 12 int dp[55][1005]; 13 bool cmp(const node &x, const node &y) { 14 return x.pos < y.pos; 15 } 16 int main() { 17 int T; 18 scanf("%d", &T); 19 while (T--) { 20 scanf("%d %d %d", &n, &m, &x); 21 for (int i = 1; i <= n; i++) { 22 for (int j = 1; j <= m; j++) { 23 scanf("%d", &a[i][j].pos); 24 } 25 } 26 for (int i = 1; i <= n; i++) { 27 for (int j = 1; j <= m; j++) { 28 scanf("%d", &a[i][j].cost); 29 } 30 } 31 for (int i = 1; i <= n; i++) { 32 sort(a[i] + 1, a[i] + 1 + m, cmp); 33 } 34 for (int j = 1; j <= m; j++) { 35 dp[1][j] = a[1][j].cost + abs(a[1][j].pos - x); 36 } 37 for (int i = 2; i <= n; i++) { 38 int k = 0, t = oo; 39 for (int j = 1; j <= m; j++) { 40 while (k + 1 <= m && a[i][j].pos >= a[i - 1][k + 1].pos) { 41 k++; 42 t = min(t, dp[i - 1][k] - a[i - 1][k].pos); 43 } 44 dp[i][j] = t + a[i][j].cost + a[i][j].pos; 45 } 46 k = m + 1, t = oo; 47 for (int j = m; j >= 1; j--) { 48 while (k - 1 >= 1 && a[i][j].pos <= a[i - 1][k - 1].pos) { 49 k--; 50 t = min(t, dp[i - 1][k] + a[i - 1][k].pos); 51 } 52 dp[i][j] = min(dp[i][j], t + a[i][j].cost - a[i][j].pos); 53 } 54 } 55 ans = oo; 56 for (int j = 1; j <= m; j++) { 57 ans = min(ans, dp[n][j]); 58 } 59 printf("%d ", ans); 60 } 61 return 0; 62 }
题意:给你n*n的方格纸,在格子里填颜色,要满足任意水平、垂直翻转,转任意个90度后看到的图形都一样;现在你有k种颜色,有m个格子已经图了颜色,求方案数。
SOL:直接搞出等价类再用快速幂做一做就好了。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int mod = 100000007; 8 const int LEN = 1e5 + 5; 9 int i, j, k, n, m, s, t, ans, tot; 10 int a[LEN]; 11 int pow_mod(const int &x, int y) { 12 if (y == 0) { 13 return 1; 14 } 15 int ans = pow_mod(x, y >> 1); 16 ans = (ll)ans * ans % mod; 17 if (y & 1) { 18 ans = (ll)ans * x % mod; 19 } 20 return ans; 21 } 22 int trans(int x, int y) { 23 if (x > n / 2) { 24 x = n + 1 - x; 25 } 26 if (y > n / 2) { 27 y = n + 1 - y; 28 } 29 if (x > y) { 30 swap(x, y); 31 } 32 return x * 10000 + y; 33 } 34 int getnum(int n) { 35 int L = (n + 1) / 2; 36 return (L + 1) * L / 2; 37 } 38 int main() { 39 while (scanf("%d %d %d", &n, &m, &k) != EOF) { 40 tot = 0; 41 for (int i = 1; i <= m; i++) { 42 int x, y; 43 scanf("%d %d", &x, &y); 44 x++, y++; 45 a[++tot] = trans(x, y); 46 } 47 if (tot > 0) { 48 sort(a + 1, a + 1 + tot); 49 tot = unique(a + 1, a + 1 + tot) - a - 1; 50 } 51 printf("%d ", pow_mod(k, getnum(n) - tot)); 52 } 53 return 0; 54 }
题意:给你一棵树,每个结点有两个属性值,1.能力值,2.忠诚度。然后m个询问,每次询问一个整数u,求u的子树中能力值大于u的且忠诚度最大的点的编号。
SOL:先按能力值排序,这样从大到小考虑就满足了条件1,然后从大到小依次在线段树里查询子树中忠诚度最大的点的编号,复杂度O(nlogn)。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #define tl (p << 1) 6 #define tr (p << 1 | 1) 7 using namespace std; 8 const int LEN = 1e5 + 5; 9 int i, j, k, n, m, s, t, tot, Time; 10 struct edge { 11 int vet, next; 12 } E[LEN * 2]; 13 struct node { 14 int x, y, id; 15 } a[LEN]; 16 bool cmp(const node &x, const node &y) { 17 return x.x > y.x; 18 }; 19 int head[LEN], size[LEN], tid[LEN], ans[LEN], pre[LEN], b[LEN]; 20 int to[1000005]; 21 int tmax[LEN * 4]; 22 void add(int u, int v) { 23 E[++tot] = (edge){v, head[u]}; 24 head[u] = tot; 25 } 26 void dfs(int u) { 27 size[u] = 1; 28 tid[u] = ++Time; 29 pre[Time] = u; 30 for (int e = head[u]; e != -1; e = E[e].next) { 31 int v = E[e].vet; 32 dfs(v); 33 size[u] += size[v]; 34 } 35 } 36 int ask(int l, int r, int x, int y, int p) { 37 if (l == x && y == r) { 38 return tmax[p]; 39 } 40 int mid = (l + r) >> 1; 41 if (mid >= y) { 42 return ask(l, mid, x, y, tl); 43 } else if (mid + 1 <= x) { 44 return ask(mid + 1, r, x, y, tr); 45 } else { 46 return max(ask(l, mid, x, mid, tl), ask(mid + 1, r, mid + 1, y, tr)); 47 } 48 } 49 void update(int p) { 50 tmax[p] = max(tmax[tl], tmax[tr]); 51 } 52 void modify(int l, int r, const int &x, int p, const int &c) { 53 if (l == r) { 54 tmax[p] = c; 55 return; 56 } 57 int mid = (l + r) >> 1; 58 if (mid >= x) { 59 modify(l, mid, x, tl, c); 60 } else { 61 modify(mid + 1, r, x, tr, c); 62 } 63 update(p); 64 } 65 void build(int l, int r, int p) { 66 if (l == r) { 67 tmax[p] = -1; 68 return; 69 } 70 int mid = (l + r) >> 1; 71 build(l, mid, tl); 72 build(mid + 1, r, tr); 73 update(p); 74 } 75 int main() { 76 int T; 77 scanf("%d", &T); 78 while (T--) { 79 tot = Time = 0; 80 scanf("%d %d", &n, &m); 81 for (int i = 1; i <= n; i++) { 82 head[i] = -1; 83 size[i] = 0; 84 tid[i] = 0; 85 } 86 a[1] = (node){1e9, 0, 1}; 87 for (int i = 2; i <= n; i++) { 88 int fa, x, y; 89 scanf("%d %d %d", &fa, &x, &y); 90 x++,y++,fa++; 91 swap(x, y); 92 add(fa, i); 93 a[i] = (node){x, y, i}; 94 to[y] = i; 95 } 96 dfs(1); 97 build(1, n, 1); 98 sort(a + 1, a + 1 + n, cmp); 99 int j = 1; 100 for (int i = 2; i <= n; i++) { 101 int x = a[i].id, t = ask(1, n, tid[x], tid[x] + size[x] - 1, 1); 102 if (t == -1) { 103 ans[x] = 0; 104 } else { 105 ans[x] = to[t]; 106 } 107 while (j + 1 <= i && a[j + 1].x > a[i + 1].x) { 108 modify(1, n, tid[a[j + 1].id], 1, a[j + 1].y); 109 j++; 110 } 111 } 112 while (m--) { 113 int x; 114 scanf("%d", &x); 115 printf("%d ", ans[x + 1] - 1); 116 } 117 } 118 return 0; 119 }