@Falsyta
2015-10-24T12:39:31.000000Z
字数 8622
阅读 1786
OI AMPPZ
虽然暂时没写完但是为了增加填坑动力还是单挂出来好了。
由于起点终点都是加油站可以只考虑加油站。
建超级源点跑最短路,考虑离每个点最近的加油站。
容易发现一个加油站
然后建出只含加油站的新图以后就转化成每次询问路径边权最小值。
# include <cstdio># include <algorithm># define REP(i, n) for (int i = 1; i <= n; ++ i)# define REP_G(i, x) for (int i = pos[x]; i; i = g[i].frt)using namespace std;const int inf = 1 << 30;# define NR 201000struct Edge {int y, frt, val; void set (int _y, int _frt, int _val) {y = _y, frt = _frt, val = _val;}} g[NR << 1];struct Arr {int x, y, w, id; Arr () {x = y = w = id = 0;} Arr (int _x, int _y, int _w, int _id): x(_x), y(_y), w(_w), id(_id) {}} e[NR << 1], qy[NR];int n, s, m, gsz, id[NR], q[5001000], fa[NR], pos[NR], dt[NR], esz, q0, ans[NR];bool inq[NR];# define v g[i].yinline bool cmpE (Arr a, Arr b) {return a.w < b.w;}inline void AE (int x, int y, int z) {g[++ gsz].set (y, pos[x], z), pos[x] = gsz;}inline int gf (int x) {return fa[x] == x ? x : (fa[x] = gf (fa[x]));}void spfa (){int head = 1, tail = 0, x;REP (i, n) id[i] ? inq[q[++ tail] = i] = true : dt[i] = inf;while (head <= tail){x = q[head ++];REP_G (i, x)if (dt[x] + g[i].val < dt[v]){dt[v] = dt[x] + g[i].val, id[v] = id[x];if (!inq[v]) inq[q[++ tail] = v] = true;}inq[x] = false;}}int main (){scanf ("%d%d%d", &n, &s, &m); int t1, t2, t3;REP (i, s) scanf ("%d", &t1), id[t1] = t1;REP (i, m) scanf ("%d%d%d", &t1, &t2, &t3), AE (t1, t2, t3), AE (t2, t1, t3);spfa ();REP (x, n) {REP_G (i, x) if (id[x] < id[v]) e[++ esz] = Arr (id[x], id[v], dt[x] + dt[v] + g[i].val, 0); fa[x] = x;}sort (e + 1, e + esz + 1, cmpE), scanf ("%d", &q0);REP (i, q0) scanf ("%d%d%d", &qy[i].x, &qy[i].y, &qy[i].w), qy[i].id = i;sort (qy + 1, qy + q0 + 1, cmpE);int j = 1;REP (i, q0){for (; j <= esz && e[j].w <= qy[i].w; ++ j) {int fx = gf (e[j].x), fy = gf (e[j].y); if (fx != fy) fa[fx] = fy;}ans[qy[i].id] = gf (qy[i].x) == gf (qy[i].y);}REP (i, q0) puts (ans[i] ? "TAK" : "NIE");return 0;}
感觉自己简直在凑数……
本来想用FWT发现没有暴力快……
复杂度
# include <cstdio># include <algorithm>using namespace std;# define REP(i, n) for (int i = 1; i <= n; ++ i)# define REP_0(i, n) for (int i = 0; i < n; ++ i)# define SR (1 << 16)# define NR 20const int inf = 1 << 30;int n, m, fi[SR], ts[SR], ans[SR], bid[SR], a[NR];int main (){scanf ("%d%d", &n, &m);int M = 1 << m;REP_0 (i, m) bid[1 << i] = i;REP_0 (i, M) fi[i] = inf;REP (i, n){scanf ("%d", &ts[0]);REP_0 (j, m) scanf ("%d", &a[j]);REP (s, M - 1) ts[s] = ts[s ^ (s & -s)] + a[bid[s & -s]], fi[s] = min (fi[s], ts[s]);}REP (i, M - 1){ans[i] = fi[i];for (int j = (i - 1) & i; j; j = (j - 1) & i) ans[i] = min (ans[i], ans[j] + ans[i - j]);}printf ("%d\n", ans[M - 1]);return 0;}
之前没看见限制……那个破翻译什么玩意啊T_T
有了限制就见了障碍就绕行就行了……
# include <cstdio># include <algorithm># define REP(i, n) for (int i = 1; i <= n; ++ i)# define pc putcharusing namespace std;# define NR 1010int p[NR], n, m, K;bool a[NR][NR], fil[NR];void ret (int x, int y){a[x][y] = true;if (x == 2 && y == 1) {pc ('D'); return ;}if (!fil[x]) {pc ('D'), ret (x - 1, y); return ;}if (y == 1) pc ('P'), fil[x] = false, ret (x, y + 1);else pc ('L'), fil[x] = false, ret (x, y - 1);}void dfs (int x, int y){a[x][y] = true;if (x == 2 && y == 1) {pc ('D'); return ;}if (x > 1 && !a[x - 1][y]){if (y == 2) for (int i = x - 1; i >= 1 && !a[i][y]; -- i) a[i][y] = fil[i] = true;else {pc ('D'), dfs (x - 1, y); return ;}}int _x = x, _y = x % 2 ? y + 1 : y - 1;if (_y == 1){if (x == n) {pc ('L'); ret (_x, _y); return ;}pc ('G'), dfs (x + 1, y); return ;}if (_y == m + 1) {pc ('G'), dfs (x + 1, y); return ;}if (a[_x][_y]) {pc ('G'), dfs (x + 1, y); return ;}x % 2 ? pc ('P') : pc ('L');dfs (_x, _y);}int main (){scanf ("%d%d%d", &n, &m, &K); int t1, t2;swap (n, m);REP (i, K) scanf ("%d%d", &t1, &t2), swap (t1, t2), a[t1][t2] = a[t1 + 1][t2] = a[t1][t2 + 1] = a[t1 + 1][t2 + 1] = true;puts ("TAK");dfs (1, 1);return 0;}
『我说啊,弱智是天生的么?』
枚举最小值
# include <cstdio># include <algorithm>using namespace std;# define REP(i, n) for (int i = 1; i <= n; ++ i)# define REP_D(i, n) for (int i = n; i >= 1; -- i)# define NR 501000int n, a[NR], pl[NR], pr[NR], ml[NR], mr[NR], il[NR], ir[NR], ql[NR], qr[NR];const int inf = 1 << 30;pair <int, int> ans;template <class T0, class T1> bool RlxN (T0 &x, T1 y) {if (x > y) return x = y, true; return false;}template <class T0, class T1> bool RlxX (T0 &x, T1 y) {if (x < y) return x = y, true; return false;}int main (){scanf ("%d", &n);pl[1] = ql[1] = 0, pr[n] = qr[n] = n + 1, ans = make_pair (-1, 1);REP (i, n) ml[i] = mr[i] = -inf;REP (i, n){scanf ("%d", &a[i]);if (i == 1) continue;int j;for (j = i - 1; j > 0 && a[j] > a[i]; j = pl[j]){if (a[j] > ml[i]) ml[i] = a[j], il[i] = j;if (ml[j] > ml[i]) ml[i] = ml[j], il[i] = il[j];}pl[i] = j;for (j = i - 1; j > 0 && a[j] < a[i]; j = ql[j]) ;ql[i] = j;}REP_D (i, n - 1){int j;for (j = i + 1; j <= n && a[j] > a[i]; j = pr[j]){if (a[j] > mr[i]) mr[i] = a[j], ir[i] = j;if (mr[j] > mr[i]) mr[i] = mr[j], ir[i] = ir[j];}pr[i] = j;for (j = i + 1; j <= n && a[j] < a[i]; j = qr[j]) ;qr[i] = j;}REP (i, n){int l0, l1, r0, r1;if (ml[i] != mr[i]) ml[i] < mr[i] ? ml[i] = -inf : mr[i] = -inf;l0 = l1 = pl[i] + 1, r0 = r1 = pr[i] - 1;if (ml[i] != -inf) RlxX (l0, il[i] + 1), RlxX (l1, ql[il[i]] + 1);if (mr[i] != -inf) RlxN (r0, ir[i] - 1), RlxN (r1, qr[ir[i]] - 1);RlxN (ans, make_pair (-(r1 - l0 + 1), l0));RlxN (ans, make_pair (-(r0 - l1 + 1), l1));}printf ("%d %d\n", -ans.first, ans.second);return 0;}
题目愣是看错了两次想了三天T_T
直接导致自己毫无输出……(明明是自己的错啦……
去掉怨念以后题目还凑活吧。
枚举答案,显然只剩下
然后我们暴力枚举每个星号的状态,然后通过看出现位置之间的间隔是否超过答案来判定。
每个出现位置能匹配的状态数应该是
于是做一次的复杂度感觉是
应该就能过了……
# include <cstdio># include <cstring># define REP(i, n) for (int i = 1; i <= n; ++ i)# define NR 3010int q0, n, li[NR], lu[NR], lt[NR], len, m, lcp[NR], z, unk[NR][30];char s[NR], tmp[NR][30], a[NR], d[30];inline bool ec (char a, char b) {return a == b || a == '*' || b == '*';}bool check (){int last = 0;REP (i, len){if (li[i] - last > z) return false;bool eql = true; REP (j, m) if (!ec (tmp[i][j], d[j])) {eql = false; break;}if (eql) last = li[i];}return true;}bool dfs (int lv){if (lv > m) return check ();d[lv] = 'R'; if (dfs (lv + 1)) return true;d[lv] = 'G'; if (dfs (lv + 1)) return true;d[lv] = 'B'; return dfs (lv + 1);}int main (){for (scanf ("%d", &q0); q0; -- q0){scanf ("%s", s + 1), n = strlen (s + 1);REP (i, n){int j = 0; lu[i] = 0;for (; i + j <= n && ec (s[1 + j], s[i + j]); ++ j)if (s[1 + j] == '*') unk[i][++ lu[i]] = i + j;lcp[i] = j;}bool succ = false;for (z = 1; z < n; ++ z){int last = 0, t = n - z + 1; bool fail = false;if (lcp[t] < z) continue;m = len = 0;REP (i, z) {a[i] = s[i]; if (a[i] == '*') a[i] = s[n - z + i], m += s[n - z + i] == '*';}REP (i, n - z + 1){if (i - last > z) {fail = true; break;}if (lcp[i] < z) continue;bool eql = true;REP (j, lu[t]) if (!ec (s[unk[i][j]], s[unk[t][j]])) {eql = false; break;}if (eql){li[++ len] = last = i; lt[len] = 0;REP (j, lu[t]) if (s[unk[t][j]] == '*') tmp[len][++ lt[len]] = s[unk[i][j]];}}if (fail) continue;if (dfs (1)){int j = 0;REP (i, z) putchar (a[i] == '*' ? d[++ j] : a[i]);succ = true; break;}}if (!succ) REP (i, n) putchar (s[i] == '*' ? 'R' : s[i]);putchar ('\n');}return 0;}
考虑拆环后用线段树维护。
对于一个区间考虑头的状态对整个区间的影响。
注意到最先开枪的后一个人的状态是确定的。
# include <cstdio># include <cstdlib># include <algorithm># include <vector>using namespace std;# define REP(i, n) for (int i = 1; i <= n; ++ i)# define REP_0(i, n) for (int i = 0; i < n; ++ i)# define REP_V(it, s) for (vector <int>::iterator it = s.begin (); it != s.end (); ++ it)# define NR 201000typedef pair <int, int> Pii;typedef int Arr[3];Pii ap[NR];int ti[NR], tp[NR], ans[NR], n, q0, csz;struct Info{Pii min; int s[3], c[3];Info () {min = make_pair (0, 0), s[0] = s[1] = s[2] = c[0] = c[1] = c[2] = 0;}Info (Pii _min, int _s0, int _s1, int _s2, int _c0, int _c1, int _c2){min = _min, s[0] = _s0, s[1] = _s1, s[2] = _s2, c[0] = _c0, c[1] = _c1, c[2] = _c2;}};# define NEXT_S(t) next[p][a.s[t]]# define u t[x]# define lc ch[0]# define rc ch[1]# define ulfc t[u.lc]# define urtc t[u.rc]# define w0 first# define w1 secondstruct Seg{int ch[2]; Info w;inline void init (Pii min) {w.min = min, w.s[0] = 0, w.s[1] = 1, w.s[2] = 2, w.c[0] = 0, w.c[1] = 0, w.c[2] = 1;}};struct SegTree{Seg *t;Arr *next;vector <int> id;int root, sz, n, N;Info merge (const Info &a, const Info &b, int p){return p %= n, Info (min (a.min, b.min),b.s[NEXT_S (0)], b.s[NEXT_S (1)], b.s[NEXT_S (2)],a.c[0] + b.c[NEXT_S (0)], a.c[1] + b.c[NEXT_S (1)], a.c[2] + b.c[NEXT_S (2)]);}int build (int l, int r){int x = ++ sz, mid = (l + r) >> 1;if (l == r) return u.init (make_pair (ti[id[l % n]], l)), x;return u.lc = build (l, mid), u.rc = build (mid + 1, r), u.w = merge (ulfc.w, urtc.w, mid), x;}void segUpd (int x, int l, int r, int p){if (l == r) {u.w.min = make_pair (ti[id[l % n]], l); return ;}int mid = (l + r) >> 1;if (p <= mid) segUpd (u.lc, l, mid, p);else segUpd (u.rc, mid + 1, r, p);u.w = merge (ulfc.w, urtc.w, mid);}Info segQry (int x, int l, int r, int ql, int qr){if (ql <= l && r <= qr) return u.w;int mid = (l + r) >> 1;if (qr <= mid) return segQry (u.lc, l, mid, ql, qr);if (ql > mid) return segQry (u.rc, mid + 1, r, ql, qr);return merge (segQry (u.lc, l, mid, ql, qr), segQry (u.rc, mid + 1, r, ql, qr), mid);}inline int getAns () {int p = t[root].w.min.w1; return segQry (root, 0, N, (p + 1) % n, (p + 1) % n + n - 1).c[0];}inline int update (int r){next[r][1] = next[r][2] = (ti[id[r % n]] > ti[id[(r + 1) % n]]);int l = (r + n - 1) % n;next[l][1] = next[l][2] = (ti[id[l % n]] > ti[id[(l + 1) % n]]);return segUpd (root, 0, N, l), segUpd (root, 0, N, r), segUpd (root, 0, N, l + n), segUpd (root, 0, N, r + n), getAns ();}inline int init (){n = id.size (), N = 2 * n - 1;t = (Seg*) malloc ((4 * n + 10) * sizeof (Seg));next = (Arr*) malloc ((n + 10) * sizeof (Arr));REP_0 (i, n) ap[id[i % n]].w1 = i % n, next[i][0] = 2, next[i][1] = next[i][2] = (ti[id[i % n]] > ti[id[(i + 1) % n]]);return root = build (0, N), getAns ();}} sol[NR];int main (){scanf ("%d", &n); int sum = 0, t1, t2;REP (i, n) scanf ("%d", &tp[i]);REP (i, n) scanf ("%d", &ti[i]);REP (i, n){if (ap[i].w0) continue;ap[i].w0 = ++ csz, sol[csz].id.clear (), sol[csz].id.push_back (i);for (int j = tp[i]; j != i; j = tp[j]) sol[csz].id.push_back (j), ap[j].w0 = csz;sum += (ans[csz] = sol[csz].init ());}printf ("%d\n", sum);scanf ("%d", &q0);REP (i, q0){scanf ("%d%d", &t1, &t2), ti[t1] = t2;int ts = ans[ap[t1].w0];printf ("%d\n", sum += (ans[ap[t1].w0] = sol[ap[t1].w0].update (ap[t1].w1)) - ts);}return 0;}