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 }

 

posted @ 2014-08-01 07:30  jams&jellies  阅读(239)  评论(0编辑  收藏  举报