[noip模拟赛]午餐
https://www.zybuluo.com/ysner/note/1325779
题面
一共有\(n\)个人,林先森知道开始时只有\(1\)号会毒瘤算法。林先森了解到很多人一起吃过
午餐;具体地,有\(m\)条信息,其中第\(j\)条信息描述\(u_j\)和\(v_j\)在\([L_j,R_j]\)区间中的某一天一起吃
了午餐。若此时\(u_j\)或\(v_j\)中的一个人会毒瘤算法,那么两个人都能学会毒瘤算法。特别地,若
一个人在某天和多个人一起吃午餐,那么他在学会毒瘤算法的同时会立即教给别人(同一天的
午餐均视作同时发生)。
林先森知道最后学会了毒瘤算法的同学以及没有学会毒瘤算法的同学,以及一些不确定是
否学会了毒瘤算法的同学。林先森想知道大家具体在哪一天共用了午餐,或者告诉林先森这样
的结果是不可能出现的。
- \(10pts\) \(n,m\leq12,R_i\leq3\)
- \(45pts\) 不存在确定没有学会毒瘤算法的同学
- \(100pts\ n,m\leq2*10^5\)
解析
做难题从部分分开始。
\(45pts\)算法
显然,如果有这条性质,可以推个贪心结论:每个人尽早学会毒瘤算法肯定是最优的。
所以可以设\(f[i]\)表示第\(i\)个人最早学会毒瘤算法的时间。
\(f[v]=\max(f[u],L)\)
然后发现转移等价于最短路。
那么拿\(Dijstra\)跑一跑就行。
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define re register
#define il inline
#define pi pair<int,int>
#define mk make_pair
#define fi first
#define se second
#define fp(i,a,b) for(re int i=a;i<=b;++i)
#define fq(i,a,b) for(re int i=a;i>=b;--i)
using namespace std;
const int N=20,M=2e5+100;
int n,m,cho[N],tar[M],top[N],mx,tag=1;
struct dat{int u,v,L,R;}a[M],sta[10][N];
bool vis[M];
int h[M],cnt,dis[M];
struct Edge{int to,nxt,mn,mx;}e[M<<1];
il void add(re int u,re int v,re int mn,re int mx)
{
e[++cnt]=(Edge){v,h[u],mn,mx};h[u]=cnt;
e[++cnt]=(Edge){u,h[v],mn,mx};h[v]=cnt;
}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void out()
{
fp(i,1,m) printf("%d\n",cho[i]);
exit(0);
}
il void check()
{
fp(i,1,n) vis[i]=0;vis[1]=1;
fp(i,1,mx)
{
fp(j,1,top[i]) if(vis[sta[i][j].u]||vis[sta[i][j].v]) vis[sta[i][j].u]=vis[sta[i][j].v]=1;
fp(j,1,top[i]) if(vis[sta[i][j].u]||vis[sta[i][j].v]) vis[sta[i][j].u]=vis[sta[i][j].v]=1;
}
re int tag=1;
fp(i,1,n) if((tar[i]==1&&!vis[i])||(tar[i]==-1&&vis[i])) {tag=0;break;}
if(tag) out();
}
il void dfs(re int x)
{
if(x>m) {check();return;}
fp(i,a[x].L,a[x].R)
{
mx=max(mx,a[x].R);
cho[x]=i;
sta[i][++top[i]]=a[x];
dfs(x+1);
--top[i];
}
}
il int min(re int x,re int y){return x<y?x:y;}
il int max(re int x,re int y){return x>y?x:y;}
il void Dijstra()
{
priority_queue<pi,vector<pi>,greater<pi> >Q;
while(!Q.empty()) Q.pop();
fp(i,1,n) vis[i]=0,dis[i]=1e9+7;
dis[1]=0;Q.push(mk(0,1));
while(!Q.empty())
{
re int u=Q.top().se;Q.pop();
vis[u]=1;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to,mx=e[i].mx,mn=e[i].mn;
if(dis[v]>max(mn,dis[u])&&dis[u]<=mx)
{
dis[v]=max(mn,dis[u]);
Q.push(mk(dis[v],v));
}
}
while(!Q.empty()&&vis[Q.top().se]) Q.pop();
}
}
il void solve()
{
memset(h,-1,sizeof(h));
fp(i,1,m) add(a[i].u,a[i].v,a[i].L,a[i].R);
Dijstra();
fp(i,1,n) if(tar[i]==1&&dis[i]>1e9) {puts("Impossible");exit(0);}
fp(i,1,m) printf("%d\n",dis[a[i].u]>a[i].R?a[i].L:max(a[i].L,dis[a[i].u]));
exit(0);
}
int main()
{
n=gi();m=gi();
fp(i,1,m)
{
a[i].u=gi(),a[i].v=gi(),a[i].L=gi(),a[i].R=gi();
}
fp(i,1,n) tar[i]=gi(),tag&=(tar[i]>=0);
if(n>12&&tag) solve();//for ex35pts
dfs(1);//for 10pts
puts("Impossible");
return 0;
}
\(100pts\)算法
直接想\(100pts\)是有难度的。
但有\(45pts\)作为铺垫就比较好想了。
如果有确定没学会的人,相当于给他周围的人(与他吃饭的人)的\(f[i]\)的下限\(lim[i]\)。
因为他们吃饭的时间一定在\(L_i\),然后\(f[i]\)就必须大于\(L_i\),即下限为\(L_i+1\)。
(接下来这点自己没想到)
然后这个下限的影响是可以扩散的。
设一个人为\(u\),和他吃饭的某人为\(v\)。
如果\(f[u]>R\),就说明\(v\)不能给\(u\)传授算法,那么他们吃饭时\(v\)不应该会算法。
为保证\(f[v]\)最小,吃饭时间一定为\(L\),则\(lim[v]\geq L+1\)。
这个过程可以用最短路维护。
在此基础上,贪心显然仍成立。
那么接着最短路转移\(f[i]\),过程中保证\(f[i]\geq lim[i]\)即可。
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define re register
#define il inline
#define pi pair<int,int>
#define mk make_pair
#define fi first
#define se second
#define fp(i,a,b) for(re int i=a;i<=b;++i)
#define fq(i,a,b) for(re int i=a;i>=b;--i)
using namespace std;
const int M=2e5+100;
int n,m,tar[M],lim[M];
struct dat{int u,v,L,R;}a[M];
bool vis[M];
int h[M],cnt,dis[M];
struct Edge{int to,nxt,mn,mx;}e[M<<1];
il void add(re int u,re int v,re int mn,re int mx)
{
e[++cnt]=(Edge){v,h[u],mn,mx};h[u]=cnt;
e[++cnt]=(Edge){u,h[v],mn,mx};h[v]=cnt;
}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il int min(re int x,re int y){return x<y?x:y;}
il int max(re int x,re int y){return x>y?x:y;}
il void Dijstra()
{
priority_queue<pi,vector<pi>,greater<pi> >Q;
while(!Q.empty()) Q.pop();
fp(i,1,n) vis[i]=0,dis[i]=1e9+7;
dis[1]=0;Q.push(mk(0,1));
while(!Q.empty())
{
re int u=Q.top().se;Q.pop();
vis[u]=1;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to,mx=e[i].mx,mn=e[i].mn,g=max(max(lim[v],mn),dis[u]);
if(dis[v]>g&&g<=mx)
{
dis[v]=g;
Q.push(mk(dis[v],v));
}
}
while(!Q.empty()&&vis[Q.top().se]) Q.pop();
}
}
il void Pre_SPFA()
{
queue<int>Q;
while(!Q.empty()) Q.pop();
fp(i,1,n)
{
tar[i]=gi();
if(tar[i]==-1) lim[i]=1e9+7,vis[i]=1,Q.push(i);
else vis[i]=0;
}
while(!Q.empty())
{
re int u=Q.front();Q.pop();
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to,mn=e[i].mn,mx=e[i].mx;
if(lim[u]>mx)
if(lim[v]<mn+1)
{
lim[v]=mn+1;
if(!vis[v]) vis[v]=1,Q.push(v);
}
}
vis[u]=0;
}
}
int main()
{
freopen("lunch.in","r",stdin);
freopen("lunch.out","w",stdout);
memset(h,-1,sizeof(h));
n=gi();m=gi();
fp(i,1,m)
{
a[i].u=gi(),a[i].v=gi(),a[i].L=gi(),a[i].R=gi();
add(a[i].u,a[i].v,a[i].L,a[i].R);
}
Pre_SPFA();
Dijstra();
fp(i,1,n)
if(tar[i]==1&&dis[i]>1e9) {puts("Impossible");exit(0);}
fp(i,1,m)
{
if(tar[a[i].u]==-1)
if(dis[a[i].v]<=a[i].L) {puts("Impossible");exit(0);}
if(tar[a[i].v]==-1)
if(dis[a[i].u]<=a[i].L) {puts("Impossible");exit(0);}
}
fp(i,1,m)
{
re int u=a[i].u,v=a[i].v;
if(tar[u]==-1||tar[v]==-1) printf("%d\n",a[i].L);
else printf("%d\n",max(dis[u],dis[v])>a[i].R?a[i].L:max(a[i].L,max(dis[u],dis[v])));
}
fclose(stdin);
fclose(stdout);
return 0;
}
[noip模拟赛]午餐的更多相关文章
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
- contesthunter暑假NOIP模拟赛第一场题解
contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...
- NOIP模拟赛 by hzwer
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...
- 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...
- 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...
- CH Round #58 - OrzCC杯noip模拟赛day2
A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...
- CH Round #52 - Thinking Bear #1 (NOIP模拟赛)
A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...
随机推荐
- BestCoder Round #79 (div.2)-jrMz and angles,,暴力求解~
jrMz and angle Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Other ...
- [NOIP2003] 提高组 洛谷P1041 传染病控制
题目背景 近来,一种新的传染病肆虐全球.蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府决定不惜一切代价控制传染病的蔓延.不幸的是,由于人们尚未完全认识这种传染病,难以准确判别病毒携带 ...
- 《effective C++》:条款07——为多态基类声明virtual析构函数
在继承中,基类的析构函数需要定义为虚析构函数数否则: (1)当派生类对象经由一个base类指针删除时,而这个base类的析构函数不是虚函数时,其结果是未定义的. (2)这样做会导致derived类部分 ...
- jquery serializeArray() 方法通过序列化表单值来创建对象数组(名称和值)。
serializeArray() 方法序列化表单元素(类似 .serialize() 方法),返回 JSON 数据结构数据. html代码: <form> <div><i ...
- [Poj2411]Mondriaan's Dream(状压dp)(插头dp)
Mondriaan's Dream Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 18096 Accepted: 103 ...
- Linux查看日志三种命令(转载)
第一种:查看实时变化的日志(比较吃内存) 最常用的: tail -f filename (默认最后10行,相当于增加参数 -n 10) Ctrl+c 是退出tail命令 其他情况: tail -n 2 ...
- makefile的语法及写法(二)
3 Makefile书写规则 -------------------------------------------------------------------------------- 规则包 ...
- [WinForm]DataGridView列头右键菜单
[WinForm]DataGridView列头右键菜单 前言 继续"不误正业" - - #,记录一下.有时候有这样的需求:DataGridView的列头菜单可以选择具体显示哪些列, ...
- LightRoom操作快捷键
1.隐藏与释放上下左右面板:F5.F6.F7.F8.分别对应上下左右面板.tab键可以隐藏与释放左右面板,shift+table可以同时隐藏与释放所有面板,T键隐藏与显示工具栏 2.图库与修改照片模块 ...
- HDU 5288(OO’s Sequence-区间互质情况统计)
OO's Sequence Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) ...