[NOIP2017模拟]证明
来源:互联网 发布:互联网大数据技术 编辑:程序博客网 时间:2024/05/22 13:22
题目背景
SOURCE:NOIP2015-HN-CJZX
题目描述
H 教授是一位德高望重的教授,也是计算机科学界的权威。他对问题总有独特而深刻的见解,治学严谨,是学术界的带头人。
在一次科学家大会上,H 教授在黑板上写下了 n 个式子
令人激动的是,没过多久,H 教授就收到了数学家们发来的 m 封 email ,第 i 封 email 写到,发信人已经证明了
H 教授希望通过这些信息证明出 P=NP 。但是,H 教授最近手头拮据,所以希望支付最小的费用。
输入格式
输入的第一行是两个整数 n,m。
接下来 m 行,每行三个整数
输出格式
输出只包含一个整数,表示 H 教授至少要支付多少元稿费,才能证明出 P=NP。如果根据现有条件无法证明 P=NP ,请输出-1。
样例数据 1
输入
9 3
1 3 101010
4 6 98889
7 9 76543
输出
-1
样例数据 2
输入
9 7
1 5 3
3 6 8
5 8 4
4 7 6
2 3 7
7 9 2
6 7 5
输出
9
备注
【样例1说明】
就算把所有的数学家都叫上,仍然证明不了 x3=x4 和 x6=x7。
【样例2说明】
第一位数学家可以证明 x1=x2=x3=x4=x5。
第三位数学家可以证明 x5=x6=x7=x8。
第六位数学家可以证明 x7=x8=x9。
这三位数学家是足够的,并且只需 9 元稿费。可以证明没有更优的方案。
【数据说明】
所有测试点的数据范围如下表所示。
分析:对数学家的证明区间排序,离散化后建图,跑dijkstra即可(SPFA要被卡),详见代码。
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<ctime>#include<cmath>#include<algorithm>#include<cctype>#include<iomanip>#include<queue>#include<set>using namespace std;int getint(){ int f=1,sum=0; char ch; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;ch>='0'&&ch<='9';ch=getchar()) sum=(sum<<3)+(sum<<1)+ch-48; return sum*f;}const int N=2e5+5,M=1e6+5;long long INF=1e17;struct node{ int l,r; long long c;}mathest[N];int n,m,b[N];int tot,first[N],nxt[M],to[M],w[M];long long dis[N];priority_queue<pair<long long,int> >que;bool comp(const node &a,const node &b){ if(a.l==b.l) return a.r<b.r; return a.l<b.l;}void lsh()//作用:将很大很大的点的下标前移,如1、4、64、8686、10000变成1、2、3、4、5{ n=0; for(int i=1;i<=m;++i) b[++n]=mathest[i].l,b[++n]=mathest[i].r; sort(b+1,b+n+1); n=unique(b+1,b+n+1)-b-1;//去重 for(int i=1;i<=m;++i) { mathest[i].l=lower_bound(b+1,b+n+1,mathest[i].l)-b; mathest[i].r=lower_bound(b+1,b+n+1,mathest[i].r)-b; }}void addedge(int x,int y,int z){ nxt[++tot]=first[x]; first[x]=tot; to[tot]=y; w[tot]=z;}void dijkstra(){ for(int i=1;i<=n;++i) dis[i]=INF; dis[1]=0; que.push(make_pair(0,1)); while(!que.empty()) { int u=que.top().second; que.pop(); for(int p=first[u];p;p=nxt[p]) { int v=to[p]; if(dis[u]+w[p]<dis[v]) { dis[v]=dis[u]+w[p]; que.push(make_pair(-dis[v],v)); } } }}int main(){ freopen("proof.in","r",stdin); freopen("proof.out","w",stdout); n=getint();m=getint(); for(int i=1;i<=m;++i) mathest[i].l=getint(),mathest[i].r=getint(),mathest[i].c=getint(); sort(mathest+1,mathest+m+1,comp); int cnt=mathest[1].r;//先判断能否证明完 for(int i=2;i<=m;i++) { if(mathest[i].l>cnt)//断节了 { cout<<-1; return 0; } cnt=max(cnt,mathest[i].r); } if(cnt<n||mathest[1].l>1)//左右边界没覆盖 { cout<<-1; return 0; } lsh();//离散化 for(int i=1;i<=m;++i) addedge(mathest[i].l,mathest[i].r,mathest[i].c);//把离散化后的左右顶点建边,权值为花费ci for(int i=2;i<=n;++i) addedge(i,i-1,0);//因为现在的所有数学家能覆盖所有数,//即被证明了两端点的中间部分是不需要花费的,就是边权为0的边,//离散化后这些点被删掉了,直接连接了某个区间(i)的右端点和另一个左端点被包含在(i)区间内的区间(j)的左端点,权值为0。//这样,如果同时选择了这两位数学家,花费才是ci+cj dijkstra(); dis[1]=INF;//如果只证明1,那显然花费不会是我们赋值的0,而是所有证明了1的人给出的最小价格 for(int i=1;i<=m;++i) if(mathest[i].l==1) dis[1]=min(dis[1],mathest[i].c); cout<<dis[n]; return 0;}
本题结。
- [NOIP2017模拟]证明
- NOIP2017赛前模拟 STAR (合理证明复杂度)
- 求hack or 证明(【JZOJ 4923】 【NOIP2017提高组模拟12.17】巧克力狂欢)
- NOIP2017模拟赛1
- NOIP2017模拟赛8
- NOIP2017模拟赛9
- [NOIP2017模拟]切蛋糕
- [NOIP2017模拟]随机图
- [NOIP2017模拟]能源
- [NOIP2017模拟]电影
- [NOIP2017模拟]鸭舌
- [NOIP2017模拟]permut
- [NOIP2017模拟]beautiful
- [NOIP2017模拟]路径
- [NOIP2017模拟]流
- [NOIP2017模拟]subset
- [NOIP2017模拟]hello
- [NOIP2017模拟]table
- Tomcat nio
- 第一个只出现一次的字符
- 用jquery简单实现打字游戏
- PHP 数组排序
- QT问题记录之warning: ‘xxx’ will be initialized after [-Wreorder]
- [NOIP2017模拟]证明
- MySQL导入和导出数据
- 数据库视频——创建数据库
- 怎么解决XAMPP中Apache80,443以及MySQL3306端口被占用
- OPENGL-学习计算机图形学
- 序列化 保存到一个文件
- 剑指offer之八---变态跳台阶
- 动态规划解152. Maximum Product Subarray
- 函数指针作函数参数/用函数指针调用函数