vijos p1782——借教室(noip2012提高组第2题)
描述
在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。
面对海量租借教室的信息,LLQ自然希望编程解决这个问题。LLQ需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借。共有m份订单,每份订单用三个正整数描述,分别为dj,sj,tj,表示某租借者需要从第sj天到第tj天租借教室(包括第sj天和第tj天),每天需要租借dj个教室。
LLQ假定,租借者对教室的大小、地点没有要求。即对于每份订单,LLQ只需要每天提供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。
借教室的原则是先到先得,也就是说LLQ要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。
现在LLQ需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。
格式
输入格式
第一行包含两个正整数n,m,表示天数和订单的数量。
第二行包含n个正整数,其中第i个数为ri,表示第i天可用于租借的教室数量。
接下来有m行,每行包含三个正整数dj,sj,tj,表示租借的数量,租借开始、结束分别在第几天。
每行相邻的两个数之间均用一个空格隔开。天数与订单均用从1开始的整数编号。
输出格式
如果所有订单均可满足,则输出只有一行,包含一个整数0。否则(订单无法完全满足)输出两行,第一行输出一个负整数-1,第二行输出需要修改订单的申请人编号。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
int m,n;
struct node{
int d,s,t;//数量,开始,结束
}k[100005];
int day[100005];
int main()
{
//ios::sync_with_stdio(false);
freopen("classroom.in","r",stdin);
freopen("classroom.out","w",stdout);
scanf("%d %d",&n,&m);//cin>>n>>m;
if(n>=100000)
{
cout<<0;
exit(0);
}
for(int i=1;i<=n;i++)
scanf("%d ",&day[i]);//cin>>day[i];
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);//cin>>x>>y>>z;
// k[i].d=x,k[i].s=y,k[i].t=z;
for(int j=y;j<=z;j++)
{
day[j]-=x;
if(day[j]<0)
{
cout<<-1<<endl;
cout<<i;
exit(0);
}
}
}
cout<<0;
return 0;
}
呵呵。。。。
二、线段树:
刚看到题肯定立马会想到这种解法,太经典了。
就是代码稍稍长了那么一丢丢。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define L(u) (u*2)
#define R(u) (u*2+1)
#define MAXN 1000005
int m,n;
int a[MAXN];int w;
using namespace std;
struct node{
int minl,x,l,r;//x:减量
}s[4*MAXN];
void pushdown(int u)
{
s[L(u)].x+=s[u].x;
s[L(u)].minl-=s[u].x;
s[R(u)].x+=s[u].x;
s[R(u)].minl-=s[u].x;
s[u].x=0;
}
void pushup(int u)
{
s[u].minl=min(s[L(u)].minl,s[R(u)].minl);
return ;
}
void buildtree(int u,int left,int right)
{
s[u].l=left,s[u].r=right;
if(left==right)
{
s[u].minl=a[left];
return ;
}
int mid=(left+right)>>1;
buildtree(L(u),left,mid);
buildtree(R(u),mid+1,right);
pushup(u);
}
void update(int u,int left,int right)
{
if(s[u].l==left&&s[u].r==right)
{
pushdown(u);
s[u].x+=w;//减量
s[u].minl-=s[u].x;
return;
}
if (s[u].x)pushdown(u);
int mid=(s[u].l+s[u].r)>>1;
if(left>mid)
update(R(u),left,right);
else if(right<=mid)
update(L(u),left,right);
else
{
update(L(u),left,mid);
update(R(u),mid+1,right);
}
pushup(u);
}
int main()
{
ios::sync_with_stdio(false);
freopen("classroom.in","r",stdin);
freopen("classroom.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
buildtree(1,1,n);
for(int i=1;i<=m;i++)
{
int x,y;
cin>>w>>x>>y;
update(1,x,y);
if(s[1].minl<0)
{
cout<<-1<<endl;
cout<<i;
exit(0);
}
}
cout<<0;
return 0;
}
这种方法思路很清晰,很好写。
三、二分求解:
一种神奇的算法。。祥解见代码中:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int r[1000005];
int d[1000005],s[1000005],t[1000005];
int a[1000005],sum[1000005];
int n,m;
bool pd(int mid)
{
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
for(int i=1;i<=mid;i++)
{
a[s[i]]+=d[i];//起点加上,终点的下一个点减去,画了图后就会发现这个方法十分的神奇~
a[t[i]+1]-=d[i];
}
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];//判断是否超过限制
if(sum[i]>r[i])return false; //超过输入数据
}
return true;//若不存在上面的情况则说明可以借
}
int main()
{
//ios::sync_with_stdio(false);
freopen("classroom.in","r",stdin);
freopen("classroom.out","w",stdout);
scanf("%d%d",&n,&m);//cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&r[i]);//cin>>r[i];
for(int i=1;i<=m;i++)
scanf("%d %d %d",&d[i],&s[i],&t[i]);//数量,起始,终点
int l=1,r=m;
while(l+1<r)
{
int mid=(l+r)>>1;
if(pd(mid))//二分查找
l=mid;
else
r=mid;
}
bool t1=pd(l),t2=pd(r);//t2=pd(r);
if(!t1)//左端点
{
printf("-1\n%d",l);
//cout<<-1<<endl;
//cout<<l;
}
else if(!t2)//右端点
{
printf("-1\n%d",r);
//cout<<-1<<endl;
//cout<<r;
}
else printf("0");//cout<<0;若都不是,则不存在修改,输出0
return 0;
}
二分最烦的就是断点取值和mid的赋值了,很容易错。这里我用的是二分到区间长度为1再判断。
完美AC~~~~~~~~~
转载于:https://www.cnblogs.com/937337156Zhang/p/5697140.html
vijos p1782——借教室(noip2012提高组第2题)相关推荐
- P1066 2^k进制数 NOIP 2006 提高组 第四题
洛谷蓝题(点击跳转) 提高组 第四题 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的 ...
- NOIP2008提高组(前三题) -SilverN
此处为前三题,第四题将单独发布 火柴棒等式 题目描述 给你n根火柴棍,你可以拼出多少个形如"A+B=C"的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0 ...
- 【NOIP2019提高组第四题】靶型数独
题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的&q ...
- 洛谷P1083 [NOIP2012提高组Day2T2]借教室
P1083 借教室 题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借 ...
- [NOIP2012提高组] CODEVS 1200 同余方程(扩展欧几里德算法)
数论题..所有数论对我来说都很恶心..不想再说什么了.. ------------------------------------------------ #include<iostream&g ...
- [NOIP2012] 提高组 洛谷P1080 国王游戏
题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍 ...
- NOIP2012 提高组 Day 2
http://www.cogs.pro/cogs/page/page.php?aid=16 期望得分:100+100+0=0 实际得分:100+20+0=120 T2线段树标记下传出错 T1 同余方程 ...
- 【NOIP2012 提高组】 国王游戏
题目: 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排成一排,国王站在队伍的最前 ...
- 游戏match(【CCF】NOI Online能力测试2 提高组第三题 )
题目背景 1s 512M 题目描述 小 A 和小 B 正在玩一个游戏:有一棵包含 n=2m个点的有根树(点从1∼n 编号),它的根是 1 号点,初始时两人各拥有 m 个点.游戏的每个回合两人都需要选出 ...
最新文章
- Python使用matplotlib绘图并去除颜色样条colorbar实战:remove colorbar from figure in matplotlib
- python windows端口检测并杀死脚本
- PHP MySQLi/PDO_MySQL/PDO_SQLite CRUD(增查改删)
- 【存储知识学习】第三章磁盘原理与技术3.4硬盘接口技术和SCSI硬盘接口--《大话存储》阅读笔记
- 【2018山东省赛 - A】Anagram(贪心,费用流,KM算法)
- guava 之 ImmutableMap 使用实例及好处
- duilib中的添加自定义控件
- 开启灯光就是近光吗_有用!科目三灯光模拟操作大全
- com 组件调用不起来_Spring Cloud Alibaba,分布式服务调用(四)
- iso图像测试卡_走进真4K |图像质量测试有哪些“硬”标准?
- AtomicReference原子性引用
- qt 不允许 dllimport 静态数据成员 的定义_C++类和对象的定义
- c语言中有关逗号表达式
- 35 红外接收头在linux内核里的驱动
- 微信小程序简单签到功能源码分享
- 手把手教你领取永久免费服务器
- vFlat Scan – 可能是最快捷的纸质书扫描应用,一次 2页,居然还能移除手指头[iOS/Android]
- 机器学习完整项目实战附代码(一):探索型数据分析+特征工程+建模+报告
- 2020笔记本性价比之王_2020十大笔记本电脑性价比排行(最新笔记本电脑推荐)...
- sqlserver关于发布订阅replication_subscription的总结