zoukankan      html  css  js  c++  java
  • 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
    ", ans);
    		else
    			printf("doge
    ");
    	}
    	return 0;
    }
    


    HDU 4893 Wow! Such Sequence!
    题意:

    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
    ",
    			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
    ", query(l, r, 1));
    			else
    				update(l, r, 1);
    		}
    		//dfs(1);
    	}
    	return 0;
    }
    


    HDU 4888 Redraw Beautiful Drawings

    题意:

    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('
    ');
    				else
    					putchar(' ');
    			}
    		}
    	}
    	return 0;
    }
    


    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    Pathfinding 模板题 /// BFS oj21413
    poj2186-Popular Cows(强连通分支)
    求有向强连通分量 模板
    F. Relatively Prime Powers (求([2,n],内不是次方的数量)
    【2018沈阳赛区网络预选赛J题】Fantastic Graph 【有上下界的网络流】
    Zoj 2314 Reactor Cooling(无源汇有上下界可行流)
    有上下界网络流模板
    有上下界网络流建模方法
    有上下界的网络流问题 的理解分析
    ACM-ICPC 2018 沈阳赛区网络预赛 D. Made In Heaven(约束第K短路)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4712983.html
Copyright © 2011-2022 走看看