首页 > 代码库 > 2014多校联合三 (HDU 4888 HDU 4891 HDU 4893)
2014多校联合三 (HDU 4888 HDU 4891 HDU 4893)
HDU 4891 The Great Pan
签到题 他怎么说你就怎么做就好了 注意做乘法时候会爆int
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; int n; char s[2000000]; int flag1, flag2, sp, ansflag; LL ans, tmp; int main() { while (scanf("%d", &n) != EOF) { getchar(); ans = 1; tmp = 0; flag1 = 0; flag2 = 0; ansflag = 1; for (int l = 1; l <= n; l++) { gets(s); int len = strlen(s); if (ansflag == 0) continue; for (int i = 0; i < len; i++) { if (flag1 == 0 && flag2 == 0 && s[i] == '{') { flag1 = 1; tmp = 0; } else if (flag1 == 1 && s[i] == '|') { tmp++; } else if (flag1 == 1 && s[i] == '}') { flag1 = 0; ans *= (tmp + 1); tmp = 1; if (ans > 1e5) { ansflag = 0; break; } } else if (flag1 == 0 && flag2 == 0 && s[i] == '$') { flag2 = 1; sp = 0; tmp = 0; } else if (flag2 == 1) { if (s[i] == '$') { if (sp == 1) { ans *= (tmp + 1); if (ans > 1e5) { ansflag = 0; break; } } flag2 = 0; tmp = 0; } else if (sp == 1 && s[i] != ' ') { ans *= (tmp + 1); if (ans > 1e5) { ansflag = 0; break; } sp = 0; tmp = 0; } else if (sp == 0 && s[i] == ' ') { tmp = 1; sp = 1; } else if (sp == 1 && s[i] == ' ') { tmp++; } } } } if (ansflag) printf("%d\n", ans); else printf("doge\n"); } return 0; }
题意:
n个数一开始都是0 你有三种操作 1操作在k位置加d 2操作输出[l,r]区间的和 3操作把[l,r]内的所有数变成离它最近最小的斐波那契数
思路:
操作1、2就是线段树基本 那么3怎么搞? 为了不超时显然要延迟更新 那么如果更新到[l,r]区间我们如何更改值呢
其实问题可以被巧妙的存储数据解决
我们记val为点上的值 toval为离他最近的斐波那契数 sum为val的和 tosum为toval的和
那么每当3操作时 我们只需要让区间的val和sum等于toval和tosum即可 在1操作时也要注意更新toval和tosum
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; #define N 100010 #define L(x) (x<<1) #define R(x) ((x<<1)|1) #define last 92 #define star 1 struct node { int l, r, lazy; LL val, toval, sum, tosum; } nd[N * 4]; LL F[N]; int n, m; LL cal(LL x) { if (x < 0) return -x; return x; } void up(int i) { nd[i].sum = nd[L(i)].sum + nd[R(i)].sum; nd[i].tosum = nd[L(i)].tosum + nd[R(i)].tosum; } void down(int i) { if (nd[i].lazy) { nd[L(i)].val = nd[L(i)].toval; nd[L(i)].sum = nd[L(i)].tosum; nd[L(i)].lazy = 1; nd[R(i)].val = nd[R(i)].toval; nd[R(i)].sum = nd[R(i)].tosum; nd[R(i)].lazy = 1; nd[i].lazy = 0; } } void init(int l, int r, int i) { nd[i].l = l; nd[i].r = r; nd[i].lazy = 0; nd[i].val = 0; nd[i].toval = 0; nd[i].sum = 0; if (l == r) { nd[i].toval = 1; nd[i].tosum = 1; return; } int mid = (l + r) >> 1; init(l, mid, L(i)); init(mid + 1, r, R(i)); up(i); } void add(int pos, int val, int i) { if (pos == nd[i].l && pos == nd[i].r) { int idx1, idx2; nd[i].val += val; idx1 = lower_bound(F + star, F + last, nd[i].val) - F; idx2 = idx1 - 1; if (cal(F[idx1] - nd[i].val) < cal(F[idx2] - nd[i].val)) { nd[i].toval = nd[i].tosum = F[idx1]; nd[i].sum = nd[i].val; } else { nd[i].toval = nd[i].tosum = F[idx2]; nd[i].sum = nd[i].val; } nd[i].lazy = 0; return; } down(i); int mid = (nd[i].l + nd[i].r) >> 1; if (pos <= mid) add(pos, val, L(i)); else add(pos, val, R(i)); up(i); } void update(int l, int r, int i) { if (l == nd[i].l && r == nd[i].r) { nd[i].val = nd[i].toval; nd[i].sum = nd[i].tosum; nd[i].lazy = 1; return; } down(i); int mid = (nd[i].l + nd[i].r) >> 1; if (r <= mid) update(l, r, L(i)); else if (l > mid) update(l, r, R(i)); else { update(l, mid, L(i)); update(mid + 1, r, R(i)); } up(i); } LL query(int l, int r, int i) { if (l == nd[i].l && r == nd[i].r) { //if(nd[i].lazy) return nd[i].tosum; //else return nd[i].sum; return nd[i].sum; } down(i); int mid = (nd[i].l + nd[i].r) >> 1; LL res = 0; if (r <= mid) res = query(l, r, L(i)); else if (l > mid) res = query(l, r, R(i)); else res = query(l, mid, L(i)) + query(mid + 1, r, R(i)); if (nd[i].l != nd[i].r) up(i); return res; } void dfs(int i) { printf("l %d r %d lazy %d val %I64d toval %I64d sum %I64d tosum %I64d\n", nd[i].l, nd[i].r, nd[i].lazy, nd[i].val, nd[i].toval, nd[i].sum, nd[i].tosum); if (nd[i].l == nd[i].r) return; dfs(L(i)); dfs(R(i)); } int main() { int i, op, l, r; F[0] = F[1] = 1; for (i = 2; i < 100; i++) F[i] = F[i - 1] + F[i - 2]; //91 7540113804746346429 // F [0 ~ 91] while (~scanf("%d%d", &n, &m)) { init(1, n, 1); for (i = 1; i <= m; i++) { scanf("%d%d%d", &op, &l, &r); if (op == 1) add(l, r, 1); else if (op == 2) printf("%I64d\n", query(l, r, 1)); else update(l, r, 1); } //dfs(1); } return 0; }
题意:
n*m的格子里面有数字0~K 现给出每一行和每一列的和 求格子里的值(唯一解时输出值 可能多解或无解)
思路:
首先要想到这题可以用网络流搞 不管从数据范围入手还是真的有思路
接着建图 (1)S->行 容量sum行 (2)列->T 容量sum列 (3)行->列 容量K 跑最大流如果满流则至少一个解
理解一下这个流就是说从行x进去的流量 经过(x,y)格子传递后 从列y出去 那么这时如果满流不就是满足题意么
接下来判断是否唯一解 可以想到 假设解不唯一 则有以下结论
从某个点开始 在这个点+g 在与它同行的某个点-g 再在新点的同列的某个点+g 一直不断延续这条路 类似这样:
+g -g
-g +g
形成一个新的解 像不像从某个点搬运了一点东西?? 然后搬一圈!! 就是这个圈所以解不唯一!!
那么我们在残余网络中dfs 如果找到一个长度>2的圈 那么必然有其他解(按着这个圈搬一搬!)
dfs最暴力即可 这是队友说的 基本都是4个点就围成圈了 点数不可能太多
PS:这是一道卡dinic时间的题! 用sap可过!
如果有巨巨用dinic过了麻烦教我一下… 从刘大师那里学来的dinic应该不会写搓…(自信???
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 810; const int MAXM = 810 * 810 * 2; const int INF = 0x3f3f3f3f; struct Node { int from, to, next; int cap; } edge[MAXM]; int tol; int head[MAXN]; int dep[MAXN]; int gap[MAXN]; int n; void init() { tol = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int w) { edge[tol].from = u; edge[tol].to = v; edge[tol].cap = w; edge[tol].next = head[u]; head[u] = tol++; edge[tol].from = v; edge[tol].to = u; edge[tol].cap = 0; edge[tol].next = head[v]; head[v] = tol++; } void BFS(int start, int end) { memset(dep, -1, sizeof(dep)); memset(gap, 0, sizeof(gap)); gap[0] = 1; int que[MAXN]; int front, rear; front = rear = 0; dep[end] = 0; que[rear++] = end; while (front != rear) { int u = que[front++]; if (front == MAXN) front = 0; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (dep[v] != -1) continue; que[rear++] = v; if (rear == MAXN) rear = 0; dep[v] = dep[u] + 1; ++gap[dep[v]]; } } } int SAP(int start, int end) { int res = 0; BFS(start, end); int cur[MAXN]; int S[MAXN]; int top = 0; memcpy(cur, head, sizeof(head)); int u = start; int i; while (dep[start] < n) { if (u == end) { int temp = INF; int inser; for (i = 0; i < top; i++) if (temp > edge[S[i]].cap) { temp = edge[S[i]].cap; inser = i; } for (i = 0; i < top; i++) { edge[S[i]].cap -= temp; edge[S[i] ^ 1].cap += temp; } res += temp; top = inser; u = edge[S[top]].from; } if (u != end && gap[dep[u] - 1] == 0) break; for (i = cur[u]; i != -1; i = edge[i].next) if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1) break; if (i != -1) { cur[u] = i; S[top++] = i; u = edge[i].to; } else { int min = n; for (i = head[u]; i != -1; i = edge[i].next) { if (edge[i].cap == 0) continue; if (min > dep[edge[i].to]) { min = dep[edge[i].to]; cur[u] = i; } } --gap[dep[u]]; dep[u] = min + 1; ++gap[dep[u]]; if (u != start) u = edge[S[--top]].from; } } return res; } int vis[MAXN]; bool sol(int u, int fa) { int i, v; vis[u] = 1; for (i = head[u]; ~i; i = edge[i].next) { v = edge[i].to; if (!edge[i].cap || v == fa) continue; if (vis[v] || sol(v, u)) return true; } vis[u] = 0; return false; } bool findcircle(int fn) { memset(vis, 0, sizeof(vis)); for (int i = 1; i <= fn; i++) { vis[i] = 1; if (sol(i, i)) return true; vis[i] = 0; } return false; } int sumx[MAXN], sumy[MAXN]; int main() { int i, j, k, n1, n2, K, amt, ans; while (~scanf("%d%d%d", &n1, &n2, &K)) { init(); sumx[0] = sumy[0] = 0; for (i = 1; i <= n1; i++) { scanf("%d", &sumx[i]); sumx[0] += sumx[i]; } for (i = 1; i <= n2; i++) { scanf("%d", &sumy[i]); sumy[0] += sumy[i]; } if (sumx[0] != sumy[0]) { puts("Impossible"); continue; } for (i = 1; i <= n1; i++) { for (j = 1; j <= n2; j++) addedge(i, n1 + j, K); } amt = tol; for (i = 1; i <= n1; i++) addedge(0, i, sumx[i]); for (i = 1; i <= n2; i++) addedge(n1 + i, n1 + n2 + 1, sumy[i]); n = n1 + n2 + 2; ans = SAP(0, n1 + n2 + 1); if (ans != sumx[0]) { puts("Impossible"); continue; } if (findcircle(n1)) puts("Not Unique"); else { puts("Unique"); for (i = 0; i < amt; i += 2) { printf("%d", K - edge[i].cap); if (edge[i].to == n1 + n2) putchar('\n'); else putchar(' '); } } } return 0; }