bzoj2330 [SCOI2011]糖果题解
2015-07-17 10:41
344 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=2330
题目大意
对这个题我真的不想再多提一句了。
n个人分糖,保证每个人都有糖,有k个限制条件,分别是a=ba=b,a<ba,a≥ba\ge b,a>ba>b,a≤ba\le b。这五种情况分别用x=1,2,3,4,5表示。求最少需要准备多少糖果。其中n,k≤106n,k\le10^6。
题解
一看就是差分约束了。
差分约束中求最小值用≥\ge,跑最长路;求最大值用≤\le,跑最短路。
x=1即a=bx=1即a=b,直接a→b,b→aa\to b,b\to a权值都是0;
x=3即a≥bx=3即a\ge b,直接b→ab\to a,权值为0;
x=5即a≤bx=5即a\le b,直接a→ba\to b,权值为0;
那么不带等号的怎么办呢?
(如果是实数可以不管,就是求得的最值取不到也在误差范围内。)
因为a,b均是整数,所以
x=2即a<b⇒a≤b−1x=2即a,然后a→ba\to b,权值为1;
同理,x=4即a>b⇒a≥b+1x=4即a>b\Rightarrow a\ge b+1,然后b→ab\to a,权值为1;
然后是与源点0连边。因为每个人都有糖,即f[i]≥1⇒f[i]−f[0]≥1f[i]\ge1\Rightarrow f[i]-f[0]\ge1,所以0→i0\to i,权值为1。
注意事项
本来是一道很裸的差分约束,但是:
某测试点是十万条边连成一条链,如果采用邻接表从表头插入的写法,从源点0连边时如果i=1→ni=1\to n,会T掉,应该i=n→1i=n\to1;
某测试点是x=2或4x=2或4时出现了a=ba=b的情况,即a>a或a<aa>a或a,这种情况应为无解,输出-1,如果不特判,你的spfa将会在毫不知情的情况下陷入死循环(就是邻接表自己连成环了);
dist数组要开longlong。
Code
题目大意
对这个题我真的不想再多提一句了。
n个人分糖,保证每个人都有糖,有k个限制条件,分别是a=ba=b,a<ba,a≥ba\ge b,a>ba>b,a≤ba\le b。这五种情况分别用x=1,2,3,4,5表示。求最少需要准备多少糖果。其中n,k≤106n,k\le10^6。
题解
一看就是差分约束了。
差分约束中求最小值用≥\ge,跑最长路;求最大值用≤\le,跑最短路。
x=1即a=bx=1即a=b,直接a→b,b→aa\to b,b\to a权值都是0;
x=3即a≥bx=3即a\ge b,直接b→ab\to a,权值为0;
x=5即a≤bx=5即a\le b,直接a→ba\to b,权值为0;
那么不带等号的怎么办呢?
(如果是实数可以不管,就是求得的最值取不到也在误差范围内。)
因为a,b均是整数,所以
x=2即a<b⇒a≤b−1x=2即a,然后a→ba\to b,权值为1;
同理,x=4即a>b⇒a≥b+1x=4即a>b\Rightarrow a\ge b+1,然后b→ab\to a,权值为1;
然后是与源点0连边。因为每个人都有糖,即f[i]≥1⇒f[i]−f[0]≥1f[i]\ge1\Rightarrow f[i]-f[0]\ge1,所以0→i0\to i,权值为1。
注意事项
本来是一道很裸的差分约束,但是:
某测试点是十万条边连成一条链,如果采用邻接表从表头插入的写法,从源点0连边时如果i=1→ni=1\to n,会T掉,应该i=n→1i=n\to1;
某测试点是x=2或4x=2或4时出现了a=ba=b的情况,即a>a或a<aa>a或a,这种情况应为无解,输出-1,如果不特判,你的spfa将会在毫不知情的情况下陷入死循环(就是邻接表自己连成环了);
dist数组要开longlong。
Code
#include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int maxn = 100010, oo = 1000000000, nil = 0; int n, k; int e, pnt[maxn], nxt[maxn << 2], u[maxn << 2], v[maxn<< 2], w[maxn << 2]; bool vis[maxn], flag; int times[maxn]; long long d[maxn]; void addedge(int a, int b, int c) { u[++e] = a; v[e] = b; w[e] = c; nxt[e] = pnt[a]; pnt[a] = e; } void init() { int x, a, b; flag = false; scanf("%d%d", &n, &k); //跑最长路的时候我喜欢直接把边权加成负的 for(int i = n; i > 0; --i) { addedge(0, i, -1); } for(int i = 1; i <= k; ++i) { scanf("%d%d%d", &x, &a, &b); switch(x) { case 1: addedge(a, b, 0); addedge(b, a, 0); break; case 2: addedge(a, b, -1); if(a == b) { flag = true; } break; case 3: addedge(b, a, 0); break; case 4: addedge(b, a, -1); if(a == b) { flag = true; } break; case 5: addedge(a, b, 0); break; default:break; } } } void work() { if(flag) { puts("-1"); return; } memset(d, 0x7f, sizeof(d)); memset(vis, 0, sizeof(vis)); memset(times, 0, sizeof(times)); queue <int> Q; d[0] = 0; vis[0] = true; ++times[0]; Q.push(0); while(!Q.empty()) { int t = Q.front(); Q.pop(); vis[t] = false; for(int j = pnt[t]; j != nil; j = nxt[j]) { if(d[v[j]] > d[t] + w[j]) { d[v[j]] = d[t] + w[j]; if(!vis[v[j]]) { vis[v[j]] = true; ++times[v[j]]; Q.push(v[j]); //因为加入了点“0”,所以总共有n+1个点 //某点第n+1次入队时才说明有负环 //虽然这里写>=n也能过 if(times[v[j]] > n) { puts("-1"); return; } } } } } long long ans = 0; for(int i = 1; i <= n; ++i) { ans += d[i]; } printf("%lld\n", -ans); } int main() { init(); work(); return 0; }
相关文章推荐
- Android 记录ListView滚动的位置的三种方法及判断是否滑动到底部
- 黑马程序员---ios学习日志2
- Sql优化
- JAVA读写文件操作
- 类对象数组
- android获得控件在屏幕中的绝对坐标 getLocationInWindow 和 getLocationOnScreen
- Highcharts可拖动式图表
- Node.js开发指南微博实例 express4x以上版本
- 1207_众数问题
- [leetcode-238]Product of Array Except Self(C语言)
- 利用Ajax读取文件并转化为数组
- app被Rejected 的各种原因翻译
- 使用友盟进行apk的自动更新
- 黑马程序员---ios学习日志3
- 在线工具收集
- auto_ptr类
- 纯javascript制作日历控件
- Jmeter性能测试NoHttpResponseException (the target server failed to respond)
- Lambda表达式详解
- PAT 数据结构 06-图8. 关键活动(30)