[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 ...
随机推荐
- HDU 3062 简单的2-SAT问题
在2-SAT,最让我纠结的还是添加有向线段的函数了 void add_clause(int i,int a,int j,int b){ int m=2*i+a; int n=2*j+b; ...
- 【01背包变形】Robberies HDU 2955
http://acm.hdu.edu.cn/showproblem.php?pid=2955 [题意] 有一个强盗要去几个银行偷盗,他既想多抢点钱,又想尽量不被抓到.已知各个银行 的金钱数和被抓的概率 ...
- ORACLE金额转换成英文大写的函数
用法如下:get_capital_money(Currency, Money) Currency: 货币或货币描述,将放在英文大写的前面: Money:金额.支持两位小数点.如果需要更多的小数点,请自 ...
- 那些“不务正业”的IT培训公司
Before First 大四下期了,现在准备找一份Java开发的实习工作,于是在各大网站上投递简历-智联招聘.51job.拉勾网,慧眼识真金的我必然会把培训机构给过滤掉,对于重庆来说招聘实习的公司少 ...
- 【POJ2774&Ural1517】Long Long Message(后缀数组)
题意:求两个字符串的最长公共子串 n<=1000 思路:这是一道论文题 ..]of longint; n,l1,l2,i,ans,m,l,r:longint; ch:ansistring; pr ...
- java打开本地应用程序(调用cmd)---Runtime用法详解
有时候我们需要借助java程序打开电脑自带的一些程序,可以直接打开或者借助cmd命令窗口打开一些常用的应用程序或者脚本,在cmd窗口执行的命令都可以通过这种方式运行. 例如: package cn.x ...
- BZOJ 2308 莫队入门经典
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2038 参考博客 https://www.cnblogs.com/Paul-Guderi ...
- 1370 - Bi-shoe and Phi-shoe(LightOJ1370)(数论基础,欧拉函数)
http://lightoj.com/volume_showproblem.php?problem=1370 欧拉函数: 在数论,对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目. φ(n) ...
- Eclipse移植项目时JDK版本不匹配Project facet Java version 1.7 is not supported
Eclipse移植项目时JDK版本不匹配Project facet Java version 1.7 is not supported 如果原有项目用的为JDK1.7,而自己的是低版本JDK,比如1. ...
- 下一代的中间件必须是支持docker规范的
下一代的中间件必须是支持docker规范的,这是中间件技术走向标准规范化的必经之路. 什么是 Docker? 答案是:Docker 是下一代的云计算模式.Docker 是下一代云计算的主流趋势. Do ...