描述

在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。

面对海量租借教室的信息,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,第二行输出需要修改订单的申请人编号。

样例输入1
4 3
2 5 4 3
2 1 3
3 2 4
4 2 4
样例输出1
-1
2
此题想出来了三解:
一、暴力求解法:
直接暴力n²,每次输出进行处理,若有小于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题)相关推荐

  1. P1066 2^k进制数 NOIP 2006 提高组 第四题

    洛谷蓝题(点击跳转) 提高组 第四题 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的 ...

  2. NOIP2008提高组(前三题) -SilverN

    此处为前三题,第四题将单独发布 火柴棒等式 题目描述 给你n根火柴棍,你可以拼出多少个形如"A+B=C"的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0 ...

  3. 【NOIP2019提高组第四题】靶型数独

    题目描述 小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低.但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的&q ...

  4. 洛谷P1083 [NOIP2012提高组Day2T2]借教室

    P1083 借教室 题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借 ...

  5. [NOIP2012提高组] CODEVS 1200 同余方程(扩展欧几里德算法)

    数论题..所有数论对我来说都很恶心..不想再说什么了.. ------------------------------------------------ #include<iostream&g ...

  6. [NOIP2012] 提高组 洛谷P1080 国王游戏

    题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍 ...

  7. NOIP2012 提高组 Day 2

    http://www.cogs.pro/cogs/page/page.php?aid=16 期望得分:100+100+0=0 实际得分:100+20+0=120 T2线段树标记下传出错 T1 同余方程 ...

  8. 【NOIP2012 提高组】 国王游戏

    题目: 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排成一排,国王站在队伍的最前 ...

  9. 游戏match(【CCF】NOI Online能力测试2 提高组第三题 )

    题目背景 1s 512M 题目描述 小 A 和小 B 正在玩一个游戏:有一棵包含 n=2m个点的有根树(点从1∼n 编号),它的根是 1 号点,初始时两人各拥有 m 个点.游戏的每个回合两人都需要选出 ...

最新文章

  1. Python使用matplotlib绘图并去除颜色样条colorbar实战:remove colorbar from figure in matplotlib
  2. python windows端口检测并杀死脚本
  3. PHP MySQLi/PDO_MySQL/PDO_SQLite CRUD(增查改删)
  4. 【存储知识学习】第三章磁盘原理与技术3.4硬盘接口技术和SCSI硬盘接口--《大话存储》阅读笔记
  5. 【2018山东省赛 - A】Anagram(贪心,费用流,KM算法)
  6. guava 之 ImmutableMap 使用实例及好处
  7. duilib中的添加自定义控件
  8. 开启灯光就是近光吗_有用!科目三灯光模拟操作大全
  9. com 组件调用不起来_Spring Cloud Alibaba,分布式服务调用(四)
  10. iso图像测试卡_走进真4K |图像质量测试有哪些“硬”标准?
  11. AtomicReference原子性引用
  12. qt 不允许 dllimport 静态数据成员 的定义_C++类和对象的定义
  13. c语言中有关逗号表达式
  14. 35 红外接收头在linux内核里的驱动
  15. 微信小程序简单签到功能源码分享
  16. 手把手教你领取永久免费服务器
  17. vFlat Scan – 可能是最快捷的纸质书扫描应用,一次 2页,居然还能移除手指头[iOS/Android]
  18. 机器学习完整项目实战附代码(一):探索型数据分析+特征工程+建模+报告
  19. 2020笔记本性价比之王_2020十大笔记本电脑性价比排行(最新笔记本电脑推荐)...
  20. sqlserver关于发布订阅replication_subscription的总结

热门文章

  1. 家里的存款以每个月六千元人民币的速度增长,这能达到什么生活水平?
  2. 男人如何在不经常锻炼的情况下,慢慢消除大肚皮,恢复好身材?
  3. 手机使用三年后不卡顿的有哪些牌子?
  4. 在沈阳存款多少可以不用工作?
  5. 如何应对倒戈的员工?
  6. 创业者总认为自己能力很强,但能力之上是认知力
  7. 男人到了中年,还是没钱没人脉,就越要有这3种心理,总会有出息
  8. 成功的捷径,学会这一点,赚钱很容易
  9. Speaking of the impact of the epidemic
  10. sort()与cmp()