Multi-University Training Contest 4
(hdoj 4897-4906)
1001
LCT和树链剖分都可以做,简单起见就说说树链剖分,LCT类似。
首先注意到一条路径上是logn条重链和logn条轻边。
当我们给一个点的所有边上的邻居边打标记时,如果该点在重链上,会影响他的轻孩子们。(要特殊考虑链头和链尾之类的)。
那么我们可以给重链上的点打标记,表示这个点的轻孩子们被翻转了没。
那么一个轻边就可以直接询问出来。复杂度:O(nlog2n)。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 #include <vector> 7 using namespace std; 8 9 const int MAX_N = int(1e5) + 10; 10 int n; 11 12 vector<int> E[MAX_N]; 13 int que[MAX_N], qh, qt, fa[MAX_N], size[MAX_N]; 14 int pathIdx[MAX_N], pathFirst[MAX_N], dep[MAX_N]; 15 16 struct Tree { 17 int l, r; 18 bool rev; 19 int sum; 20 21 Tree*pl, *pr; 22 23 void applyRev() { 24 rev ^= 1; 25 sum = r - l - sum; 26 } 27 28 void relax() { 29 if (rev) { 30 pl->applyRev(), pr->applyRev(); 31 rev = false; 32 } 33 } 34 35 void update() { 36 sum = pl->sum + pr->sum; 37 } 38 39 Tree(int l, int r) : 40 l(l), r(r), rev(false) { 41 sum = 0; 42 if (l + 1 == r) { 43 pl = pr = 0; 44 return; 45 } 46 pl = new Tree(l, l + r >> 1), pr = new Tree(l + r >> 1, r); 47 } 48 49 int querySum(int L, int R) { 50 if (L >= R) 51 return 0; 52 if (L <= l && R >= r) 53 return sum; 54 if (L >= r || l >= R) 55 return 0; 56 relax(); 57 return pl->querySum(L, R) + pr->querySum(L, R); 58 } 59 60 void reverse(int L, int R) { 61 if (L >= R) 62 return; 63 if (L <= l && R >= r) { 64 applyRev(); 65 return; 66 } 67 if (L >= r || l >= R) 68 return; 69 relax(); 70 pl->reverse(L, R), pr->reverse(L, R); 71 update(); 72 } 73 }; 74 75 Tree*sumTree[MAX_N], *markTree[MAX_N]; 76 77 void build(int vs) { //build path-composition 78 qh = qt = 0; 79 que[qt++] = vs, fa[vs] = -1, dep[vs] = 0; 80 while (qh < qt) { 81 int u = que[qh++]; 82 vector<int>::iterator v; 83 for(v=E[u].begin(); v!=E[u].end(); v++) 84 if (*v != fa[u]) { 85 fa[*v] = u, que[qt++] = *v, dep[*v] = dep[u] + 1; 86 } 87 } 88 for (int i = n - 1; i >= 0; --i) { 89 int u = que[i]; 90 size[u] = 1; 91 vector<int>::iterator v; 92 for(v=E[u].begin(); v!=E[u].end(); v++) 93 if (fa[*v] == u) 94 size[u] += size[*v]; 95 } 96 97 memset(pathFirst, -1, sizeof pathFirst); 98 for (int i = 0; i < n; ++i) { 99 int u = que[i]; 100 if (pathFirst[u] != -1) 101 continue; 102 int top = u, cnt = 0; 103 for (;;) { 104 pathFirst[u] = top; 105 pathIdx[u] = cnt++; 106 107 int nxt = -1; 108 vector<int>::iterator v; 109 for(v=E[u].begin(); v!=E[u].end(); v++) 110 if (fa[*v] == u) 111 if (nxt == -1 || size[*v] > size[nxt]) { 112 nxt = *v; 113 } 114 if (nxt == -1) 115 break; 116 u = nxt; 117 } 118 sumTree[top] = new Tree(0, cnt); 119 markTree[top] = new Tree(0, cnt); 120 } 121 } 122 123 int col[MAX_N]; //for light edge u and u's father 124 125 int getLightEdge(int u) { 126 //u and fa[u] is a light edge, get its weight 127 int v = fa[u]; 128 return col[u] ^ markTree[pathFirst[v]]->querySum(pathIdx[v], pathIdx[v] + 1); 129 } 130 131 int query(int x, int y) { 132 int ret = 0; 133 for (;;) { 134 if (pathFirst[x] == pathFirst[y]) { 135 int l = pathIdx[x], r = pathIdx[y]; 136 if (l > r) 137 swap(l, r); 138 ret += sumTree[pathFirst[x]]->querySum(l + 1, r + 1); 139 break; 140 } 141 if (dep[pathFirst[x]] < dep[pathFirst[y]]) 142 swap(x, y); 143 //x goest first 144 ret += sumTree[pathFirst[x]]->querySum(1, pathIdx[x] + 1); 145 x = pathFirst[x]; 146 ret += getLightEdge(x); 147 x = fa[x]; 148 } 149 return ret; 150 } 151 152 void reversePath(int x, int y) { 153 for (;;) { 154 if (pathFirst[x] == pathFirst[y]) { 155 int l = pathIdx[x], r = pathIdx[y]; 156 if (l > r) 157 swap(l, r); 158 sumTree[pathFirst[x]]->reverse(l + 1, r + 1); 159 break; 160 } 161 if (dep[pathFirst[x]] < dep[pathFirst[y]]) 162 swap(x, y); 163 //x goest first 164 sumTree[pathFirst[x]]->reverse(1, pathIdx[x] + 1); 165 x = pathFirst[x]; 166 col[x] ^= 1; 167 x = fa[x]; 168 } 169 } 170 171 void reverseAdj(int x, int y) { 172 for (;;) { 173 if (pathFirst[x] == pathFirst[y]) { 174 int l = pathIdx[x], r = pathIdx[y]; 175 if (l > r) 176 swap(l, r), swap(x, y); 177 markTree[pathFirst[x]]->reverse(l, r + 1); 178 if (pathFirst[x] == x) 179 col[x] ^= 1; 180 else 181 sumTree[pathFirst[x]]->reverse(l, l + 1); 182 183 sumTree[pathFirst[y]]->reverse(r + 1, r + 2); 184 break; 185 } 186 if (dep[pathFirst[x]] < dep[pathFirst[y]]) 187 swap(x, y); 188 //x goest first 189 markTree[pathFirst[x]]->reverse(0, pathIdx[x] + 1); 190 sumTree[pathFirst[x]]->reverse(pathIdx[x] + 1, pathIdx[x] + 2); 191 x = pathFirst[x]; 192 col[x] ^= 1; 193 x = fa[x]; 194 } 195 } 196 197 int main() { 198 int T; 199 scanf("%d",&T); 200 while (T--) { 201 scanf("%d",&n); 202 for (int i = 0; i < n; ++i) { 203 E[i].clear(); 204 } 205 memset(col, 0, sizeof col); 206 for (int i = 0; i < n - 1; ++i) { 207 int a, b; 208 scanf("%d %d",&a,&b); 209 --a, --b; 210 E[a].push_back(b), E[b].push_back(a); 211 } 212 213 build(0); 214 215 int Q; 216 scanf("%d",&Q); 217 while (Q--) { 218 int t, a, b; 219 scanf("%d%d%d", &t, &a, &b), --a, --b; 220 if (t == 1) { 221 reversePath(a, b); 222 } else if (t == 2) { 223 reverseAdj(a, b); 224 } else { 225 printf("%d\n", query(a, b)); 226 } 227 } 228 } 229 }
1002
首先二分答案,并且注意到一个点开始的子串越长字典序越大。
那么现在问题变成了给你一个环,每个点i能往后延伸长度ri,问存不存在一个 从某点跳k次绕一圈跳回自己的路径。
首先递归删掉ri = 0的点,因为这些点不能经过。那么现在所有点的r都>0,那么如果还有n个点,那么最多跳n次。注意到可行次数显然是一个区间,那么只要求出最小跳的次数就行了。
最小跳的次数就是枚举一个开始点然后不停往后狂跳。
ADD
n ≤ 10w的话怎么做?
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 #include <vector> 7 using namespace std; 8 const int MAX_N = 4000 + 10; 9 char S[MAX_N]; 10 int n, k; 11 int lcp[MAX_N][MAX_N]; 12 13 struct Sub { 14 int l, r; //[l,r) 15 16 Sub(int l, int r) : 17 l(l), r(r) { 18 } 19 20 int size() { 21 return r - l; 22 } 23 char charAt(int x) { 24 if (x < size()) 25 return S[l + x]; 26 else 27 return 0; 28 } 29 }; 30 31 int Lcp(Sub a, Sub b) { 32 return min(lcp[a.l][b.l], min((int) a.size(), (int) b.size())); 33 } 34 35 bool operator<(Sub a, Sub b) { 36 int L = Lcp(a, b); 37 return a.charAt(L) < b.charAt(L); 38 } 39 40 int step[MAX_N]; 41 42 bool check(Sub M) { 43 vector<int> nxt(n); 44 for (int i = 0; i < n; ++i) { 45 int L = Lcp(Sub(i, i + n), M); 46 if (S[(i + L) % n] < M.charAt(L)) 47 nxt[i] = n; 48 else 49 nxt[i] = L; 50 } 51 52 // for (int i = 0; i < n; ++i) { 53 // cout << nxt[i] << " "; 54 // } 55 // cout << endl; 56 //clean 57 for (;;) { 58 bool done = true; 59 for (int i = 0; i < nxt.size(); ++i) { 60 if (nxt[i] == 0) { 61 for (int j = 0; j < nxt.size(); ++j) 62 if (j != i) { 63 if (j < i && j + nxt[j] >= i) 64 --nxt[j]; 65 else if (j > i && j + nxt[j] >= i + nxt.size()) 66 --nxt[j]; 67 } 68 nxt.erase(nxt.begin() + i); 69 done = false; 70 break; 71 } 72 } 73 if (done) 74 break; 75 } 76 77 // for (int i = 0; i < nxt.size(); ++i) { 78 // cout << nxt[i] << " "; 79 // } 80 // cout << endl; 81 82 if (k > nxt.size()) 83 return false; 84 85 for (int i = 0; i < nxt.size() * 2; ++i) { 86 step[i] = i + nxt[i % nxt.size()]; 87 } 88 89 for (int i = 0; i < nxt.size(); ++i) { 90 int need = 0, at = i; 91 while (at < i + nxt.size()) { 92 at = step[at]; 93 ++need; 94 } 95 if (need <= k) 96 return true; 97 } 98 99 return false; 100 } 101 102 int main() { 103 int T; 104 scanf("%d",&T); 105 while (T--) { 106 scanf("%d %d",&n,&k); 107 108 memset(S, 0, sizeof S); 109 110 scanf("%s", S); 111 112 for (int i = n; i < n + n; ++i) { 113 S[i] = S[i - n]; 114 } 115 116 for (int i = n + n - 1; i >= 0; --i) { 117 for (int j = n + n - 1; j >= 0; --j) { 118 if (S[i] == S[j]) 119 lcp[i][j] = lcp[i + 1][j + 1] + 1; 120 else 121 lcp[i][j] = 0; 122 } 123 } 124 125 vector<Sub> subs; 126 for (int i = 0; i < n; ++i) { 127 for (int j = i; j < i + (i == 0 ? n : n - 1); ++j) { 128 subs.push_back(Sub(i, j + 1)); 129 } 130 } 131 sort(subs.begin(), subs.end()); 132 133 int l = -1, r = subs.size() - 1; 134 while (l + 1 < r) { 135 int m = (l + r) >> 1; 136 if (check(subs[m])) 137 r = m; 138 else 139 l = m; 140 } 141 142 Sub ans = subs[r]; 143 for (int i = 0; i < ans.size(); ++i) { 144 printf("%c", ans.charAt(i)); 145 } 146 puts(""); 147 // check(ans); 148 } 149 return 0; 150 }
1003
考虑dpi,j 表示S的前i个和T 的前j个的LCT。 注意到,如果我们枚举了一个长度为i的串,我们关心哪些信息?有意义的只有dpi,∗的值!对于i,我们暴力记录所有dpi,∗的值来。
注意到dpi,j 和dpi,j−1最多差1,因此状态数量很少。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 #include <vector> 7 #include <map> 8 using namespace std; 9 const int MOD = int(1e9) + 7; 10 string S; 11 int m; 12 const string ACGT = "ACGT"; 13 14 vector<int> getNext(vector<int> cur, char c) { 15 for (int i = S.size(); i >= 1; --i) { 16 if (S[i - 1] == c) 17 cur[i] = max(cur[i - 1] + 1, cur[i]); 18 } 19 for (int i = 1; i <= S.size(); ++i) { 20 cur[i] = max(cur[i], cur[i - 1]); 21 } 22 return cur; 23 } 24 25 map<vector<int>, int> idmp; 26 vector<vector<int> > states; 27 28 void dfs(vector<int> cur) { 29 if (idmp.count(cur)) 30 return; 31 32 int me = idmp.size(); 33 idmp[cur] = me; 34 states.push_back(cur); 35 36 for (int i = 0; i < ACGT.size(); ++i) { 37 dfs(getNext(cur, ACGT[i])); 38 } 39 } 40 41 vector<vector<int> > trans; 42 43 void addIt(int&x, int c) { 44 x += c; 45 if (x >= MOD) 46 x -= MOD; 47 } 48 49 int calcStates(string S) { 50 ::S = S; 51 idmp.clear(), states.clear(); 52 vector<int> init(S.size() + 1, 0); 53 dfs(init); 54 return states.size(); 55 } 56 57 int maxState; 58 string who; 59 60 void dfs(string cur, int rem, int nused) { 61 if (rem == 0) { 62 int tmp = calcStates(cur); 63 // maxState = max(maxState, calcStates(cur)); 64 if (tmp > maxState) { 65 maxState = tmp; 66 who = cur; 67 } 68 return; 69 } 70 for (int i = 0; i < 4 && i <= nused; ++i) { 71 dfs(cur + ACGT[i], rem - 1, max(nused, i + 1)); 72 } 73 } 74 75 int main() { 76 int T; 77 cin >> T; 78 while (T--) { 79 cin >> S; 80 cin >> m; 81 82 idmp.clear(), states.clear(); 83 84 vector<int> init(S.size() + 1, 0); 85 dfs(init); 86 trans.assign(idmp.size(), vector<int>(4, 0)); 87 88 for (int i = 0; i < states.size(); ++i) { 89 for (int j = 0; j < 4; ++j) { 90 trans[i][j] = idmp[getNext(states[i], ACGT[j])]; 91 } 92 } 93 94 vector<int> am(states.size(), 0); 95 vector<int> nam = am; 96 97 am[idmp[init]] = 1; 98 99 for (int i = 0; i < m; ++i) { 100 fill(nam.begin(), nam.end(), 0); 101 for (int a = 0; a < states.size(); ++a) { 102 for (int b = 0; b < 4; ++b) { 103 addIt(nam[trans[a][b]], am[a]); 104 } 105 } 106 am = nam; 107 } 108 109 vector<int> ans(S.size() + 1, 0); 110 for (int i = 0; i < states.size(); ++i) { 111 addIt(ans[states[i].back()], am[i]); 112 } 113 114 for (int i = 0; i <= S.size(); ++i) { 115 cout << ans[i] << endl; 116 } 117 } 118 }
1004
不妨枚举a,b作为直径,然后计算该情况的概率。注意到如果不考虑字典序这其实等价于其它选的点满足Dc→a ≤ Da→b 并且 Dc→b ≤ Da→b。
考虑字典序也类似。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 #include <vector> 7 using namespace std; 8 9 const int MAX_N = 1000 + 10; 10 int n, k; 11 int lab[MAX_N]; 12 int dist[MAX_N][MAX_N], ans[MAX_N][MAX_N]; 13 14 vector<int> E[MAX_N]; 15 16 int cnt[MAX_N]; 17 18 void dfs(int u, int p, int d, int w, int dst[], int am[]) { 19 20 if (++cnt[lab[u]] == 1) 21 ++w; 22 23 dst[u] = d; 24 am[u] = w; 25 vector<int>::iterator x; 26 for(x=E[u].begin(); x!=E[u].end(); x++) 27 if (*x != p) 28 dfs(*x, u, d + 1, w, dst, am); 29 30 --cnt[lab[u]]; 31 } 32 33 typedef int T; 34 struct Index: public vector<T> { 35 void doit() { 36 sort(begin(), end()); 37 erase(unique(begin(), end()), end()); 38 } 39 int get(T x) { 40 return lower_bound(begin(), end(), x) - begin(); 41 } 42 }; 43 44 double comb[MAX_N][MAX_N]; 45 46 int main() { 47 for (int i = 0; i < MAX_N; ++i) { 48 for (int j = 0; j <= i; ++j) { 49 comb[i][j] = 50 (i == 0 || j == 0) ? 51 1 : (comb[i - 1][j] + comb[i - 1][j - 1]); 52 } 53 } 54 55 int T; 56 cin >> T; 57 while (T--) { 58 cin >> n >> k; 59 for (int i = 0; i < n; ++i) { 60 E[i].clear(); 61 } 62 for (int i = 0; i < n - 1; ++i) { 63 int a, b; 64 cin >> a >> b, --a, --b; 65 E[a].push_back(b); 66 E[b].push_back(a); 67 } 68 69 Index idx; 70 71 for (int i = 0; i < n; ++i) { 72 cin >> lab[i]; 73 idx.push_back(lab[i]); 74 } 75 76 idx.doit(); 77 78 for (int i = 0; i < n; ++i) { 79 lab[i] = idx.get(lab[i]); 80 } 81 82 memset(cnt, 0, sizeof cnt); 83 84 for (int i = 0; i < n; ++i) { 85 dfs(i, -1, 0, 0, dist[i], ans[i]); 86 } 87 88 if (k == 1) { 89 printf("%0.10lf\n", 0.); 90 continue; 91 } 92 93 double ans = 0; 94 95 for (int a = 0; a < n; ++a) { 96 for (int b = a + 1; b < n; ++b) { 97 int cnt = 0; 98 for (int c = 0; c < n; ++c) 99 if (a != c && b != c) { 100 int L = dist[a][b]; 101 if (dist[a][c] > L || (dist[a][c] == L && c < b)) 102 continue; 103 if (dist[b][c] > L || (dist[b][c] == L && c < a)) 104 continue; 105 ++cnt; 106 } 107 double pb = comb[cnt][k - 2] / comb[n][k]; 108 ans += pb * ::ans[a][b]; 109 } 110 } 111 112 printf("%0.10lf\n", ans); 113 } 114 }
1005
大家肯定会做吧。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 using namespace std; 7 8 const int MAX_N = int(1e3) + 10; 9 const int MOD = int(1e9) + 7; 10 int dp1[MAX_N][1024], dp2[MAX_N][1024], n, a[MAX_N]; 11 12 void addIt(int&x, int c) { 13 x += c; 14 if (x >= MOD) 15 x -= MOD; 16 } 17 18 int main() { 19 int T; 20 cin >> T; 21 for (int it = 0; it < T; ++it) { 22 cin >> n; 23 for (int i = 0; i < n; ++i) { 24 cin >> a[i]; 25 } 26 memset(dp1, 0, sizeof dp1); 27 28 dp1[0][0] = 1; 29 for (int i = 0; i < n; ++i) { 30 for (int j = 0; j < 1024; ++j) { 31 if (dp1[i][j] > 0) { 32 addIt(dp1[i + 1][j], dp1[i][j]); 33 addIt(dp1[i + 1][j ^ a[i]], dp1[i][j]); 34 } 35 } 36 } 37 memset(dp2, 0, sizeof dp2); 38 39 dp2[n][1023] = 1; 40 for (int i = n - 1; i >= 0; --i) { 41 for (int j = 0; j < 1024; ++j) { 42 if (dp2[i + 1][j] > 0) { 43 addIt(dp2[i][j], dp2[i + 1][j]); 44 addIt(dp2[i][j & a[i]], dp2[i + 1][j]); 45 } 46 } 47 } 48 int ans = 0; 49 for (int i = 0; i < n; ++i) { 50 for (int j = 0; j < 1024; ++j) { 51 int w1 = dp1[i + 1][j]; 52 addIt(w1, MOD - dp1[i][j]); 53 int w2 = dp2[i + 1][j]; 54 if (j == 1023) { //delete the case T is empty 55 addIt(w2, MOD - 1); 56 } 57 addIt(ans, 1LL * w1 * w2 % MOD); 58 } 59 } 60 cout << ans << endl; 61 } 62 }
1006
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 #include <map> 7 using namespace std; 8 9 const int MAX_N = int(1e5) + 10; 10 int a[MAX_N], n; 11 12 struct Tree { 13 Tree*pl, *pr; 14 int l, r; 15 16 pair<int, int> mx; //value,position 17 18 bool same; 19 int samev; 20 21 void update() { 22 mx = max(pl->mx, pr->mx); 23 } 24 25 void apply(int v) { 26 same = true; 27 samev = v; 28 mx = make_pair(v, l); 29 } 30 31 void relax() { 32 if (same) { 33 pl->apply(samev); 34 pr->apply(samev); 35 same = false; 36 } 37 } 38 39 Tree(int l, int r) : 40 l(l), r(r) { 41 same = false; 42 if (l + 1 == r) { 43 mx = make_pair(a[l], l); 44 return; 45 } 46 pl = new Tree(l, l + r >> 1); 47 pr = new Tree(l + r >> 1, r); 48 update(); 49 } 50 51 void change(int L, int R, int x) { 52 if (L <= l && R >= r) { 53 apply(x); 54 return; 55 } 56 if (L >= r || l >= R) 57 return; 58 relax(); 59 pl->change(L, R, x); 60 pr->change(L, R, x); 61 update(); 62 } 63 64 pair<int, int> query(int L, int R) { 65 if (L <= l && R >= r) { 66 return mx; 67 } 68 if (L >= r || l >= R) 69 return make_pair(-1, 0); 70 relax(); 71 return max(pl->query(L, R), pr->query(L, R)); 72 } 73 74 void print(int a[]) { 75 if (l + 1 == r) { 76 a[l] = mx.first; 77 return; 78 } 79 relax(); 80 pl->print(a), pr->print(a); 81 } 82 }*rt; 83 84 struct Cover { 85 map<int, int> mp; 86 87 void init(int l, int r, int init) { //[l,r) 88 mp[l] = mp[r] = init; 89 } 90 91 int get_value(int x) { 92 map<int, int>::iterator it = --mp.upper_bound(x); 93 int v = it->second; 94 int l = it->first; 95 int r = (++it)->first; 96 // return make_tuple(v, l, r); 97 return v; 98 } 99 100 pair<int, int> get_range(int x) { 101 map<int, int>::iterator it = --mp.upper_bound(x); 102 int v = it->second; 103 int l = it->first; 104 int r = (++it)->first; 105 // return make_tuple(v, l, r); 106 // return v; 107 return make_pair(l, r); 108 } 109 110 void cover(int l, int r, int w) { 111 //[l,r) 112 // int old = ::get<0>(get(r)); 113 int old = get_value(r); 114 mp.erase(mp.lower_bound(l), mp.upper_bound(r)); 115 mp[l] = w; 116 mp[r] = old; 117 } 118 }; 119 120 int main() { 121 int T; 122 cin >> T; 123 while (T--) { 124 cin >> n; 125 Cover cv; 126 cv.init(0, n, 0); 127 for (int i = 0; i < n; ++i) { 128 cin >> a[i]; 129 cv.cover(i, i + 1, a[i]); 130 } 131 rt = new Tree(0, n); 132 133 int Q; 134 cin >> Q; 135 while (Q--) { 136 int t, l, r, x; 137 cin >> t >> l >> r >> x; 138 --l; 139 if (t == 1) { 140 rt->change(l, r, x); 141 cv.cover(l, r, x); 142 } else { 143 for (;;) { 144 pair<int, int> mx = rt->query(l, r); 145 if (mx.first <= x) 146 break; 147 pair<int, int> t = cv.get_range(mx.second); 148 int L = t.first, R = t.second; //[l,r) 149 L = max(L, l); 150 R = min(R, r); 151 int v = __gcd(mx.first, x); 152 rt->change(L, R, v); 153 cv.cover(L, R, v); 154 } 155 } 156 } 157 rt->print(a); 158 for (int i = 0; i < n; ++i) { 159 cout << a[i] << " "; 160 } 161 cout << endl; 162 } 163 }
1007
首先我们不妨枚举所有点的距离标号,> k的就看成k + 1就可以了。 然后考虑一个距离标号为b的点。
对于一个标号为a的点,如果a < b,那么a到b的边要≥ b − a,并且需要存在一个点使得那条边是b − a。
这个可以用dp来计算方案数。 当然这样复杂度还是不够,注意到其实没必要枚举点的具体标号,只要分别枚举每种标号的点有几个就可以了。
ADD
有多项式算法吗?
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 using namespace std; 7 8 const int MAX_N = 10 + 10; 9 const int MOD = int(1e9) + 7; 10 int n, k, L; 11 int cnt[MAX_N]; 12 int comb[MAX_N][MAX_N]; 13 int pw[MAX_N * MAX_N]; 14 15 int ans; 16 17 void addIt(int&x, int c) { 18 x += c; 19 if (x >= MOD) 20 x -= MOD; 21 } 22 23 int calcDp(int i) { 24 int dp[MAX_N][2] = { }; 25 int o = 0; 26 dp[o][0] = 1; 27 28 for (int j = 0; j < i; ++j) { 29 for (int it = 0; it < cnt[j]; ++it) { 30 int minL = i - j; 31 if (minL > L) 32 return 0; 33 int upd[2] = { L - minL, 1 }; 34 for (int u = 0; u < 2; ++u) { 35 for (int v = 0; v < 2; ++v) { 36 addIt(dp[o + 1][u | v], 1LL * dp[o][u] * upd[v] % MOD); 37 } 38 } 39 ++o; 40 } 41 } 42 43 // w *= dp[o][1]; 44 int one = dp[o][1]; 45 if (i == k + 1) 46 addIt(one, dp[o][0]); 47 48 return one; 49 } 50 51 int calc() { 52 int w = 1; //calculate the way 53 int rem = n - 2; 54 for (int i = 1; i <= k + 1; ++i) { 55 int need = cnt[i]; 56 if (i == k) 57 --need; 58 w = 1LL * w * comb[rem][need] % MOD; 59 rem -= need; 60 } 61 62 // for (int i = 0; i <= k + 1; ++i) { 63 // cout << cnt[i] << " "; 64 // } 65 // cout << endl; 66 67 //calcualte the way to put it 68 for (int i = 1; i <= k + 1; ++i) 69 if (cnt[i] > 0) { 70 int dp[MAX_N][2] = { }; 71 int o = 0; 72 dp[o][0] = 1; 73 74 for (int j = 0; j < i; ++j) { 75 for (int it = 0; it < cnt[j]; ++it) { 76 int minL = i - j; 77 if (minL > L) 78 return 0; 79 int upd[2] = { L - minL, 1 }; 80 for (int u = 0; u < 2; ++u) { 81 for (int v = 0; v < 2; ++v) { 82 addIt(dp[o + 1][u | v], 83 1LL * dp[o][u] * upd[v] % MOD); 84 } 85 } 86 ++o; 87 } 88 } 89 90 // w *= dp[o][1]; 91 int one = dp[o][1]; 92 if (i == k + 1) 93 addIt(one, dp[o][0]); 94 95 int t = cnt[i]; 96 97 for (int j = 0; j < t; ++j) { 98 w = 1LL * w * one % MOD; 99 } 100 w = 1LL * w * pw[t * (t - 1) / 2] % MOD; 101 } 102 // ans += 103 // addIt(ans, w); 104 return w; 105 } 106 107 void search(int at, int rem, int w) { 108 if (at == k + 2) { 109 if (rem == 0) { 110 addIt(ans, w); 111 // cout << w << " " << calc() << endl; 112 } 113 return; 114 } 115 int one = calcDp(at); 116 if (at != k) { 117 for (int now = 0; now <= rem; ++now) { 118 cnt[at] = now; 119 search(at + 1, rem - now, 1LL * w * comb[rem][now] % MOD); 120 w = 1LL * w * one % MOD * pw[now] % MOD; 121 if (w == 0) 122 break; 123 } 124 } else { 125 w = 1LL * w * one % MOD; 126 127 for (int now = 0; now <= rem; ++now) { 128 cnt[at] = now + 1; 129 search(at + 1, rem - now, 1LL * w * comb[rem][now] % MOD); 130 w = 1LL * w * one % MOD * pw[now + 1] % MOD; 131 if (w == 0) 132 break; 133 } 134 } 135 } 136 137 int main() { 138 for (int i = 0; i < MAX_N; ++i) { 139 for (int j = 0; j <= i; ++j) { 140 comb[i][j] = 141 (i == 0 || j == 0) ? 142 1 : (comb[i - 1][j] + comb[i - 1][j - 1]) % MOD; 143 } 144 } 145 146 int T; 147 scanf("%d",&T); 148 while (T--) { 149 scanf("%d %d %d",&n,&k,&L); 150 151 pw[0] = 1; 152 for (int i = 1; i <= n * n; ++i) { 153 pw[i] = 1LL * pw[i - 1] * L % MOD; 154 } 155 156 memset(cnt, 0, sizeof cnt); 157 ans = 0; 158 cnt[0] = 1; 159 search(1, n - 2, 1); 160 161 printf("%d\n",ans); 162 } 163 }
1008
如果知道了该点离a,b中的a近一点,这实际上意味着确定了一个半平面,左侧是该点可能的区域。
我们不妨枚举离该点第二近的是哪个,再枚举第一近的是哪个,然后平面切割出这种情况下的多边形。
然后进行简单的积分就能计算出答案了。
ADD
第k远当然也是可做的。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <vector> 8 using namespace std; 9 10 const double EPS = 1e-8; 11 inline int sign(double a) { 12 return a < -EPS ? -1 : a > EPS; 13 } 14 15 struct Point { 16 double x, y; 17 Point() { 18 } 19 Point(double _x, double _y) : 20 x(_x), y(_y) { 21 } 22 Point operator+(const Point&p) const { 23 return Point(x + p.x, y + p.y); 24 } 25 Point operator-(const Point&p) const { 26 return Point(x - p.x, y - p.y); 27 } 28 Point operator*(double d) const { 29 return Point(x * d, y * d); 30 } 31 Point operator/(double d) const { 32 return Point(x / d, y / d); 33 } 34 bool operator<(const Point&p) const { 35 int c = sign(x - p.x); 36 if (c) 37 return c == -1; 38 return sign(y - p.y) == -1; 39 } 40 double dot(const Point&p) const { 41 return x * p.x + y * p.y; 42 } 43 double det(const Point&p) const { 44 return x * p.y - y * p.x; 45 } 46 double alpha() const { 47 return atan2(y, x); 48 } 49 double distTo(const Point&p) const { 50 double dx = x - p.x, dy = y - p.y; 51 return hypot(dx, dy); 52 } 53 double alphaTo(const Point&p) const { 54 double dx = x - p.x, dy = y - p.y; 55 return atan2(dy, dx); 56 } 57 void read() { 58 scanf("%lf%lf", &x, &y); 59 } 60 double abs() { 61 return hypot(x, y); 62 } 63 double abs2() { 64 return x * x + y * y; 65 } 66 void write() { 67 cout << "(" << x << "," << y << ")" << endl; 68 } 69 Point rot90() { 70 return Point(-y, x); 71 } 72 }; 73 74 #define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y)) 75 76 #define crossOp(p1,p2,p3) sign(cross(p1,p2,p3)) 77 78 Point isSS(Point p1, Point p2, Point q1, Point q2) { 79 double a1 = cross(q1,q2,p1), a2 = -cross(q1,q2,p2); 80 return (p1 * a2 + p2 * a1) / (a1 + a2); 81 } 82 83 vector<Point> convexCut(const vector<Point>&ps, Point q1, Point q2) { 84 vector<Point> qs; 85 int n = ps.size(); 86 for (int i = 0; i < n; ++i) { 87 Point p1 = ps[i], p2 = ps[(i + 1) % n]; 88 int d1 = crossOp(q1,q2,p1), d2 = crossOp(q1,q2,p2); 89 if (d1 >= 0) 90 qs.push_back(p1); 91 if (d1 * d2 < 0) 92 qs.push_back(isSS(p1, p2, q1, q2)); 93 } 94 return qs; 95 } 96 97 double calcArea(const vector<Point>&ps) { 98 int n = ps.size(); 99 double ret = 0; 100 for (int i = 0; i < n; ++i) { 101 ret += ps[i].det(ps[(i + 1) % n]); 102 } 103 return ret / 2; 104 } 105 106 vector<Point> convexHull(vector<Point> ps) { 107 int n = ps.size(); 108 if (n <= 1) 109 return ps; 110 sort(ps.begin(), ps.end()); 111 vector<Point> qs; 112 for (int i = 0; i < n; qs.push_back(ps[i++])) { 113 while (qs.size() > 1 && crossOp(qs[qs.size()-2],qs.back(),ps[i]) <= 0) 114 qs.pop_back(); 115 } 116 for (int i = n - 2, t = qs.size(); i >= 0; qs.push_back(ps[i--])) { 117 while (qs.size() > t && crossOp(qs[qs.size()-2],qs.back(),ps[i]) <= 0) 118 qs.pop_back(); 119 } 120 qs.pop_back(); 121 return qs; 122 } 123 124 typedef vector<Point> Poly; 125 126 Poly background(double X, double Y) { //[0,X] * [0,Y] 127 Poly ret; 128 ret.push_back(Point(0, 0)); 129 ret.push_back(Point(X, 0)); 130 ret.push_back(Point(X, Y)); 131 ret.push_back(Point(0, Y)); 132 return ret; 133 } 134 135 const int MAX_N = 100 + 1; 136 137 Poly BIG; 138 int n, X, Y; 139 Point ps[MAX_N]; 140 141 Poly getNear(Poly ps, Point a, Point b) { //get the part near a 142 Point p1 = (a + b) / 2, p2 = p1 + (b - a).rot90(); 143 return convexCut(ps, p1, p2); 144 } 145 146 double cut(Poly ps, double x) { 147 double ly = 1e100, ry = -1e100; 148 for (int i = 0; i < ps.size(); ++i) { 149 Point p1 = ps[i], p2 = ps[(i + 1) % ps.size()]; 150 if (p1.x > p2.x) 151 swap(p1, p2); 152 if (sign(x - p1.x) >= 0 && sign(p2.x - x) >= 0) { 153 double a = x - p1.x, b = p2.x - x; 154 double y = (b * p1.y + a * p2.y) / (a + b); 155 ly = min(ly, y); 156 ry = max(ry, y); 157 } 158 } 159 return ry - ly; 160 } 161 162 double sqr(double x) { 163 return x * x; 164 } 165 166 double calc(Poly ps, double x) { 167 vector<double> ix; 168 for (int i = 0; i < ps.size(); ++i) { 169 ix.push_back(ps[i].x); 170 } 171 sort(ix.begin(), ix.end()); 172 double ret = 0; 173 for (int i = 0; i + 1 < ix.size(); ++i) { 174 double l = ix[i], r = ix[i + 1]; 175 double m1 = (l * 2 + r) / 3, m2 = (l + r * 2) / 3; 176 double v = sqr(l - x) * cut(ps, l) + sqr(m1 - x) * cut(ps, m1) * 3 177 + sqr(m2 - x) * cut(ps, m2) * 3 + sqr(r - x) * cut(ps, r); 178 v /= 8; 179 v *= r - l; 180 ret += v; 181 } 182 return ret; 183 } 184 185 double integrate(Poly ps, Point p) { 186 double ret = calc(ps, p.x); 187 for (int i = 0; i < ps.size(); ++i) { 188 swap(ps[i].x, ps[i].y); 189 } 190 ret += calc(ps, p.y); 191 return ret; 192 } 193 194 int main() { 195 int T; 196 scanf("%d",&T); 197 while (T--) { 198 scanf("%d %d %d",&n,&X,&Y); 199 BIG = background(X, Y); 200 for (int i = 0; i < n; ++i) { 201 ps[i].read(); 202 } 203 204 double sum = 0; 205 206 for (int second = 0; second < n; ++second) { 207 for (int first = 0; first < n; ++first) 208 if (first != second) { 209 Poly py = BIG; 210 py = getNear(py, ps[first], ps[second]); 211 for (int i = 0; i < n; ++i) 212 if (i != first && i != second) { 213 py = getNear(py, ps[second], ps[i]); 214 if (calcArea(py) <= 1e-8) 215 break; 216 } 217 sum += integrate(py, ps[second]); 218 } 219 } 220 221 printf("%0.10lf\n", sum / X / Y); 222 } 223 }
1009
四边形不等式优化存在一定问题,暂时没有解法
1010
和C类似,直接存到目前为止,哪些数可以被拼出来。
ADD
有更好的做法吗?
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <string> 6 using namespace std; 7 int n, k, L; 8 9 const int MAX_K = 20, MOD = int(1e9) + 7; 10 11 void addIt(int&x, int c) { 12 x += c; 13 if (x >= MOD) 14 x -= MOD; 15 } 16 17 int dp[1 << MAX_K]; 18 19 int main() { 20 int T; 21 scanf("%d",&T); 22 while (T--) { 23 scanf("%d %d %d",&n,&k,&L); 24 memset(dp, 0, sizeof dp); 25 dp[0] = 1; 26 int extra = 0; 27 if (L > k) { 28 extra = L - k; 29 L = k; 30 } else { 31 } 32 int mask = (1 << k) - 1; 33 for (int i = 0; i < n; ++i) { 34 for (int j = (1 << k) - 1; j >= 0; --j) { 35 int c = dp[j]; 36 if (c == 0) 37 continue; 38 for (int o = 1; o <= L; ++o) { 39 int nj = j | ((j << o) & mask) | (1 << (o - 1)); 40 // dp[nj] += c; 41 addIt(dp[nj], c); 42 } 43 addIt(dp[j], 1LL * c * extra % MOD); 44 } 45 } 46 int ans = 0; 47 for (int i = 0; i < (1 << k); ++i) { 48 if (i >> (k - 1) & 1) 49 addIt(ans, dp[i]); 50 } 51 cout << ans << endl; 52 } 53 return 0; 54 }
转载于:https://www.cnblogs.com/jams-jellies/p/3884053.html
Multi-University Training Contest 4相关推荐
- Sichuan University Programming Contest 2018 Preliminary
嗯为了防止大家AK,所以这次的A题和K题我们就当做不存在好了! 经历了昨天写了两个多小时的博客没保存的心态炸裂,今天终于下了个Markdown.所以我猜这篇的格式应该会更好看一点! 好吧废话不多说 题 ...
- HDU 6091 - Rikka with Match | 2017 Multi-University Training Contest 5
思路来自 某FXXL 不过复杂度咋算的.. /* HDU 6091 - Rikka with Match [ 树形DP ] | 2017 Multi-University Training Conte ...
- HDU 6051 - If the starlight never fade | 2017 Multi-University Training Contest 2
/* HDU 6051 - If the starlight never fade [ 原根,欧拉函数 ] | 2017 Multi-University Training Contest 2 题意: ...
- HDU 6058 - Kanade's sum | 2017 Multi-University Training Contest 3
/* HDU 6058 - Kanade's sum [ 思维,链表 ] | 2017 Multi-University Training Contest 3 题意:给出排列 a[N],求所有区间的第 ...
- 2017 Multi-University Training Contest - Team 3 Kanade's sum hd6058
地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6058 题目: Kanade's sum Time Limit: 4000/2000 MS (J ...
- 2018 Multi-University Training Contest 3 Problem F. Grab The Tree 【YY+BFS】
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6324 Problem F. Grab The Tree Time Limit: 2000/1000 MS ...
- hdu 4925 Apple Tree--2014 Multi-University Training Contest 6
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4925 Apple Tree Time Limit: 2000/1000 MS (Java/Others ...
- HUST-2015 Multi-University Training Contest 9
2015 Multi-University Training Contest 9 solutions BY xudyh 1001.Expression 记dp_{l,r}dpl,r表示l,rl, ...
- 2018 Multi-University Training Contest 4 Problem E. Matrix from Arrays 【打表+二维前缀和】
任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6336 Problem E. Matrix from Arrays Time Limit: 4000/20 ...
- 2017 Multi-University Training Contest - Team 1
2017 Multi-University Training Contest - Team 1 01 签到的 #include<bits/stdc++.h> using names ...
最新文章
- Linux I2C工具查看配置I2C设备【转】
- 带你一起学kivy第一天
- SpringCloud接入EDAS——服务发现篇
- 基于Ubuntu Hadoop的群集搭建Hive
- js阻止ajax继续请求,js 拦截全局 ajax 请求
- 使用requests请求网页时,返回的页面信息有时是乱码,如下代码
- Spring整合Mongodb,Maven的依赖,Spring配置,MongoDB的公共操作类,使用SpringMVC的Controller进行测试并返回结果的案例
- Linux/unix 查看端口占用
- spring事务三大接口
- 圆形界面 开启相机_「基础篇三」手机摄影拍照界面详解
- 数据库并发一致性案例分析(存取钱)
- java字符串常量存哪里_浅谈JAVA中字符串常量的储存位置
- 5ecsgo启动失败2错误代码2_Xcode 10.2 编译失败,如何对敌?
- php 动态引用dll文件路径,win平台环境变量与dll动态链接库搜索路径小结
- C++实现一个不能被继承的类
- 向数据库插入数据时出现乱码 --设置连接数据库的编码
- Vue:vue将按需引入element抽成单独js文件
- CUDA 优化之 PReLU 性能调优
- 站内搜索引擎(ASP.NET)
- blender玻璃材质