[NOI 2014]做题记录
【NOI2014】起床困难综合症
按位贪心
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 100010 using namespace std; int n, m; int tp[maxn], v[maxn]; int getans(int final, int p){ for(int i = 1; i <= n; i ++){ if(tp[i] == 0)final &= v[i]; if(tp[i] == 1)final |= v[i]; if(tp[i] == 2)final ^= v[i]; }return final >> p & 1; } bool check(int x){ if(getans(0, x) >= getans(1 << x, x)) return 0; return 1; } int solve(int final){ for(int i = 1; i <= n; i ++){ if(tp[i] == 0)final &= v[i]; if(tp[i] == 1)final |= v[i]; if(tp[i] == 2)final ^= v[i]; }return final; } int main(){ scanf("%d%d", &n, &m); char cmd[5]; int x; for(int i = 1; i <= n; i ++){ scanf("%s%d", cmd, &x); if(cmd[0] == 'A')tp[i] = 0; if(cmd[0] == 'O')tp[i] = 1; if(cmd[0] == 'X')tp[i] = 2; v[i] = x; } int log = 1; for(; 1ll << log <= m; log ++);log --; int ans = 0; for(int i = log; i >= 0; i --) if((ans | (1 << i)) <= m && check(i)) ans = ans | (1 << i); printf("%d\n", solve(ans)); return 0; }
【NOI2014】魔法森林
最小增量生成树
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define maxn 200010 using namespace std; int n, m; struct Edge_{ int u, v, a, b; void read(){scanf("%d%d%d%d", &u, &v, &a, &b);} bool operator<(const Edge_& k)const{ return a < k.a; } }G[maxn]; int L[maxn], R[maxn]; int val[maxn], c[maxn][2], fa[maxn], pos[maxn]; bool rev[maxn]; namespace Splay{ #define l c[x][0] #define r c[x][1] int st[maxn], top; void init(){ memset(val, 0x80, sizeof val); for(int i = 1; i <= 2 * n; i ++) pos[i] = i; } void pushup(int x){ pos[x] = x; if(val[pos[x]] < val[pos[l]]) pos[x] = pos[l]; if(val[pos[x]] < val[pos[r]]) pos[x] = pos[r]; } void pushdown(int x){ if(rev[x]){ rev[x] = 0; rev[l] ^= 1; rev[r] ^= 1; swap(l, r); } } void rotate(int p, int x){ int mark = p == c[x][1], y = c[p][mark ^ 1]; int z = fa[x]; if(x == c[z][0])c[z][0] = p; if(x == c[z][1])c[z][1] = p; if(y)fa[y] = x; fa[p] = z; c[p][mark ^ 1] = x; fa[x] = p; c[x][mark] = y; pushup(x); } bool isroot(int p){ return c[fa[p]][0] != p && c[fa[p]][1] != p; } void splay(int p){ st[top = 1] = p; for(int i = p; !isroot(i); i = fa[i]) st[++ top] = fa[i]; for(;top; top --) pushdown(st[top]); while(!isroot(p)){ int x = fa[p], y = fa[x]; if(isroot(x))rotate(p, x); else if(p == c[x][0] ^ x == c[y][0]) rotate(p, x), rotate(p, y); else rotate(x, y), rotate(p, x); } pushup(p); } #undef l #undef r } namespace LCT{ void Access(int u){ int t = 0; while(u){ Splay::splay(u); c[u][1] = t; t = u; u = fa[u]; } } void Evert(int u){ Access(u); Splay::splay(u); rev[u] ^= 1; } void link(int u, int v, int t){ Evert(v); fa[v] = t; Evert(t); fa[t] = u; } void cut(int u, int v, int t){ Evert(t); Access(u); Splay::splay(u); c[u][0] = fa[t] = 0; Evert(t); Access(v); Splay::splay(v); c[v][0] = fa[t] = 0; } int find(int u){ Access(u); Splay::splay(u); while(c[u][0])u = c[u][0]; return u; } int ask(int u, int v){ if(find(u) != find(v)) return -1; Evert(u); Access(v); Splay::splay(v); return pos[v]; } } int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= m; i ++) G[i].read(); sort(G + 1, G + 1 + m); Splay::init(); int ans = 0x7fffffff; int cnt = n; for(int i = 1; i <= m; i ++){ int t = LCT::ask(G[i].u, G[i].v); if(t == -1){ t = ++ cnt; L[t] = G[i].u; R[t] = G[i].v; val[t] = G[i].b; fa[t] = c[t][0] = c[t][1] = 0; pos[t] = t; LCT::link(L[t], R[t], t); } else if(val[t] > G[i].b){ LCT::cut(L[t], R[t], t); L[t] = G[i].u; R[t] = G[i].v; val[t] = G[i].b; fa[t] = c[t][0] = c[t][1] = 0; pos[t] = t; LCT::link(L[t], R[t], t); } t = LCT::ask(1, n); if(t != -1) ans = min(ans, val[t] + G[i].a); //cout << ans << ' ' << val[t] << ' ' << G[i].a << ' ' << G[i].b << endl; } if(ans > 1000000) ans = -1; printf("%d\n", ans); return 0; }
【NOI2014】动物园
KMP
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 1000010 #define mod 1000000007ll using namespace std; int nxt[maxn], n; char c[maxn]; int p[maxn]; long long ans; void solve(){ p[1] = 1; nxt[0] = nxt[1] = 0; for(int i = 2; i <= n; i ++){ int j = nxt[i - 1]; while(j && c[i] != c[j + 1])j = nxt[j]; if(c[i] == c[j + 1])j ++; nxt[i] = j; p[i] = p[j] + 1; } int j = 0; ans = 1; for(int i = 2; i <= n; i ++){ while(j && c[i] != c[j + 1])j = nxt[j]; if(c[i] == c[j + 1])j ++; while(j * 2 > i)j = nxt[j]; ans = 1ll * (p[j] + 1) * ans % mod; } printf("%lld\n", ans); } int main(){ int test; scanf("%d", &test); while(test --){ scanf("%s", c + 1); n = strlen(c + 1); solve(); } return 0; }
【NOI2014】随机数生成器
把序列搞出来每次取最小值看是否可以添加进去
每一行可取的范围是连续的,维护Li和Ri就可以判定
#include <algorithm> #include <stdio.h> typedef long long ll; int x0, a, b, c, d; int n, m, q; int T[25000001], mp[5001][5001]; int l[5001], r[5001]; int Rand(){ x0 = ((ll)a * x0 * x0 % d + (ll)b * x0 + c) % d; return x0; } int main(){ scanf("%d%d%d%d%d", &x0, &a, &b, &c, &d); scanf("%d%d%d", &n, &m, &q); int k = n * m; for(int i = 1; i <= k; i ++) T[i] = i; for(int i = 1; i <= k; i ++) std::swap(T[i], T[Rand() % i + 1]); int x, y; for(int i = 1; i <= q; i ++) scanf("%d%d", &x, &y), std::swap(T[x], T[y]); int nw = 0; for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) mp[i][j] = T[++ nw]; for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) T[mp[i][j]] = i << 16 | j; for(int i = 1; i <= n; i ++) l[i] = 1, r[i] = m; bool flag = false; for(int i = 1; i <= k; i ++){ x = T[i] >> 16; y = T[i] & 65535; if(l[x] <= y && y <= r[x]){ if(flag)putchar(' '); flag = true; printf("%d", i); for(int j = 1; j < x; j ++)r[j] = std::min(r[j], y); for(int j = x + 1; j <= n; j ++)l[j] = std::max(l[j], y); } } return 0; }
【NOI2014】购票
树剖+三分
long long 乘 long long乘爆了。。
改成double才过
凸包不要建错
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #define maxn 200010 using namespace std; typedef long long ll; int n; struct Edge{ int to, nxt; ll dis; }edge[maxn]; int h[maxn], cnt; void add(int u, int v, ll d){ edge[++ cnt] = (Edge){v, h[u], d}; h[u] = cnt; } const ll inf = 1ll << 60; const int root = 1; ll p[maxn], q[maxn], L[maxn], dis[maxn], dp[maxn]; int fa[maxn], anc[maxn][20]; int top[maxn], son[maxn], pos[maxn], size[maxn], dfs_clock; void dfs1(int u){ size[u] = 1; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u])continue; anc[v][0] = fa[v] = u; dis[v] = dis[u] + edge[i].dis; dfs1(v); size[u] += size[v]; if(size[v] > size[son[u]]) son[u] = v; } } void dfs2(int u, int tp){ pos[u] = ++ dfs_clock; top[u] = tp; if(son[u])dfs2(son[u], tp); for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u] || v == son[u])continue; dfs2(v, v); } } int Find(int u, ll d){ for(int i = 18; i >= 0; i --) if(dis[anc[u][i]] >= d) u = anc[u][i]; return u; } #define lc id << 1 #define rc id << 1 | 1 vector<int> t[maxn << 2]; void update(int id, int l, int r, int u){ int top = t[id].size() - 1; while(top > 0){ int t1 = t[id][top], t2 = t[id][top - 1]; if((double)(dp[u] - dp[t1]) / (dis[u] - dis[t1]) < (double)(dp[u] - dp[t2]) / (dis[u] - dis[t2])) top --, t[id].pop_back(); else break; } t[id].push_back(u); if(l == r)return; int mid = l + r >> 1; if(pos[u] <= mid)update(lc, l, mid, u); else update(rc, mid+1, r, u); } ll pd(int i, int u){return dp[i] + (dis[u] - dis[i]) * p[u] + q[u];} ll check(int id, int u){ int l = 0, r = t[id].size() - 1; ll ret = inf; while(r - l >= 3){ int m1 = (l + l + r) / 3, m2 = (l + r + r) / 3; if(pd(t[id][m1], u) > pd(t[id][m2], u)) l = m1; else r = m2; } for(int i = l; i <= r; i ++) ret = min(ret, pd(t[id][i], u)); return ret; } ll ask(int id, int l, int r, int L, int R, int u){ if(l == L && r == R)return check(id, u); int mid = l + r >> 1; if(R <= mid)return ask(lc, l, mid, L, R, u); if(L > mid) return ask(rc, mid+1, r, L, R, u); return min(ask(lc, l, mid, L, mid, u), ask(rc, mid+1, r, mid+1, R, u)); } ll query(int u){ ll d = dis[u] - L[u], ret = inf; int nw = u; u = fa[u]; while(u){ if(dis[u] < d)break; int l = pos[top[u]], r = pos[u]; if(dis[top[u]] < d)l = pos[Find(u, d)]; ret = min(ret, ask(1, 1, n, l, r, nw)); u = fa[top[u]]; }return ret; } void solve(int u){ if(u != 1)dp[u] = query(u); update(1, 1, n, u); for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa[u])continue; solve(v); } } int main(){ int test; scanf("%d%d", &n, &test); int f; ll s; for(int i = 2; i <= n; i ++){ scanf("%d%lld%lld%lld%lld", &f, &s, &p[i], &q[i], &L[i]); add(f, i, s); } dfs1(root); dfs2(root, root); for(int j = 1; 1 << j <= n; j ++) for(int i = 1; i <= n; i ++) anc[i][j] = anc[anc[i][j-1]][j-1]; solve(root); for(int i = 2; i <= n; i ++) printf("%lld\n", dp[i]); return 0; }
给时光以生命,而不是给生命以时光。