NOIP试题解析

NOIP试题解析           by QTY_YTQ

noip2010关押罪犯(并查集)

题意是有n个罪犯关在两个监狱中,其中有m对罪犯有仇恨关系,如果有仇恨的罪犯关在一起会产生一定影响力的事件,要求安排罪犯位置使产生影响力最大的事件影响最小。

可以用并查集来做,每个罪犯抽象为两个点,一个表示该罪犯关押在1监狱,另一个表示该罪犯关押在2监狱,我们将罪犯仇恨关系按影响的大小排序,每次选取影响力最大的一对罪犯(x,y),尽可能不让它们在一个监狱内,将x1和y2合并,将x2和y1合并,继续往后做,知道两个罪犯已经在同一集合内,这时不能让这两个罪犯在不同监狱中,则他们之间的影响力就是最小的最大影响力,

代码:

program prison;
var
  a,b,c:array[0..100000]of longint;
  f:array[0..40000]of longint;
  n,i,m,x,y,v,x1,y1,x2,y2:longint;
function find(x:longint):longint;
var i,j,k:longint;
begin
  i:=x; j:=i;
  while f[i]<>i do i:=f[i];
  while j<>i do
  begin k:=f[j];f[j]:=i; j:=k; end;
  exit(i);
end;
procedure qsort(l,r:longint);
var i,j,m,t:longint;
begin
  i:=l; j:=r; m:=c[(l+r) div 2];
  repeat
   while c[i]>m do inc(i);
   while c[j]<m do dec(j);
   if i<=j then
    begin
      t:=c[i]; c[i]:=c[j]; c[j]:=t;
      t:=a[i]; a[i]:=a[j]; a[j]:=t;
      t:=b[i]; b[i]:=b[j]; b[j]:=t;
      inc(i); dec(j);
    end;
  until i>j;
  if j>l then qsort(l,j);
  if i<r then qsort(i,r);
end;
begin
  readln(n,m);
  for i:=1 to n*2 do f[i]:=i;
  for i:=1 to m do
   begin
     readln(x,y,v);
     a[i]:=x; b[i]:=y; c[i]:=v;
   end;
  qsort(1,m);
  for i:=1 to m do
   begin
     x1:=find(a[i]); x2:=find(a[i]+n);
     y1:=find(b[i]); y2:=find(b[i]+n);
     if (x1<>y1)and(x2<>y2) then begin f[x2]:=y1; f[y2]:=x1; end
      else begin writeln(c[i]); n:=-1;break;  end;
   end;
  if n>=0 then writeln(0);
end.

noip2011选择客栈(思考+rmq)

题意是有n个客栈排成一排,每种客栈有一个颜色,共k种颜色,有两个人要住在同种颜色的不同客栈中,并且要到这两个客栈之间(包括这两个客栈)的某家客栈喝咖啡,并且花费不超过p,求满足该条件的住宿方案数。

主要思路是,先rmqst算法得到任意两客栈之间客栈喝咖啡的最小花费,可以看出,如果选择i客栈和j客栈最小花费不超过p,则选择i客栈和j以后客栈的最小花费必然不超过p,选择i之前客栈和j客栈的最小花费也不超过p,那么我们从1做到n,对于客栈i,对应颜色x,先判断它左边最靠近它的颜色是x一个客栈与该客栈之间的最小花费是否超过p,超过则计数器直接加上之前满足某一方案且颜色为x的客栈数,没超过则加上i之前颜色为x的客栈总数,得到答案。

代码:

program hotel;
var
  h:array[0..20,0..200000]of longint;
  a,b:array[0..200000]of longint;
  pl:array[0..20]of longint;
  r,c,u:array[0..50]of longint;
  n,i,m,j,k,p,x,s:longint;
function min(x,y:longint):longint;
begin
   if x<y then min:=x else min:=y;
end;
function find(x,y:longint):longint;
var j:longint;
begin
  j:=trunc(ln(y-x+1)/ln(2));
  exit(min(h[j,x],h[j,y-pl[j]+1]));
end;
begin
 assign(input,‘hotel.in‘);
reset(input);
assign(output,‘hotel.out‘);
rewrite(output);
  readln(n,k,p);
  for i:=1 to n do
   readln(b[i],a[i]);
  pl[0]:=1;
  for i:=1 to trunc(ln(n)/ln(2)) do  pl[i]:=pl[i-1]*2;
  for i:=1 to n do  h[0,i]:=a[i];
  for i:=1 to trunc(ln(n)/ln(2)) do
    for j:=1 to n+1-2*i do
     h[i,j]:=min(h[i-1,j],h[i-1,j+pl[i-1]]);
  for i:=1 to n do
   begin
     x:=b[i];
     if u[x]=0 then begin r[x]:=i;u[x]:=1; end
      else
       begin
         k:=find(r[x],i);
         if k<=p then begin c[x]:=u[x];u[x]:=u[x]+1;s:=s+c[x];r[x]:=i; end
          else begin  s:=s+c[x]; u[x]:=u[x]+1; r[x]:=i; end;
       end;
   end;
 writeln(s);
 close(input); close(output);
end.

noip2011聪明的质监员(二分)

题意什么的按题目来,需要注意的每个区间的值是由该区间上重量超过w矿石个数乘上该区间重量超过w矿石的价值和。

二分答案,然后前缀和得到区间上超过w矿石的价值和与数量和,然后判断比s大还是小,利用w越大,y越小的单调性变换上下界。

代码:

program qc;
var
  w,v,x,y,s1,s2:array[0..200000]of int64;
  n,i,m,l,r,mid:longint; s,x1,x2:int64;
function find(k:longint):int64;
var i,j:longint;  sum:int64;
begin
  sum:=0;
  fillchar(s1,sizeof(s1),0); fillchar(s2,sizeof(s2),0);
  for i:=1 to n do
  begin s1[i]:=s1[i-1]+ord(w[i]>=k)*v[i];s2[i]:=s2[i-1]+ord(w[i]>=k); end;
  for i:=1 to m do
    sum:=sum+(s1[y[i]]-s1[x[i]-1])*(s2[y[i]]-s2[x[i]-1]);
  exit(sum);
end;
begin
  assign(input,‘qc.in‘);
reset(input);
assign(output,‘qc.out‘);
rewrite(output);
  readln(n,m,s);
  for i:=1 to n do
  begin  readln(w[i],v[i]); if w[i]>r then r:=w[i]; end;
  for i:=1 to m do
   readln(x[i],y[i]);l:=1;
  while l<=r do
   begin
     mid:=(l+r) div 2;
     if find(mid)<=s then r:=mid-1 else l:=mid+1;
   end;
  x1:=find(l); x2:=find(r);
  if abs(x1-s)<abs(x2-s) then writeln(abs(x1-s)) else writeln(abs(x2-s));
  close(input); close(output);
end.

noip2012借教室(二分+前缀和)

题意是每天有一些教室可以租借,有m份请求分别要租借一定数量教室一段时间,输出最先无法满足的请求序号。

二分答案,利用前缀和记录不同时间租借教室的个数,判断是否满足。

代码:

program classroom;
var
  f,d,s,t,b:array[0..1000000]of int64;
  n,i,m,k,l,r,mid,ans:longint;  sum:int64;
begin
  assign(input,‘classroom.in‘);
  reset(input);
  assign(output,‘classroom.out‘);
   rewrite(output);
  readln(n,m);
  for i:=1 to n do read(f[i]);
  for i:=1 to m do
   readln(d[i],s[i],t[i]);
  l:=0; r:=m;
  while l<=r do
   begin
     mid:=(l+r) div 2;
     fillchar(b,sizeof(b),0);
     for i:=1 to mid do
       begin
         inc(b[s[i]],d[i]);inc(b[t[i]+1],-d[i]);
       end;
     sum:=0;  k:=0;
     for i:=1 to n do
      begin
        sum:=sum+b[i]; if sum>f[i] then begin k:=1; break; end;
      end;
     if k=1 then r:=mid-1
       else begin ans:=mid; l:=mid+1; end;
   end;
  if ans>=m then writeln(0)
   else begin writeln(-1); writeln(ans+1); end;
  close(input); close(output);
end.

noip2013火柴排队(贪心+逆序对)

题意两组火柴,同组火柴高度不同,分别将两组火柴以两两交换形式得到新序列,使两组火柴同位置火柴高度差绝对值和最小,求最少交换次数。

显然1组第一高的火柴要对应2组第一高的火柴,第二高也对应第二高,以此类推,我们对火柴高度离散化后,以一组火柴为参照,求另一组火柴高度逆序对个数即可。

代码:

program match;
type
  arr=array[0..100002]of longint;
var
  a,b,u,v,bit:arr;
  n,i,m:longint; t:int64;
procedure add(i,x:longint);
begin
  while i<=n do
   begin
     bit[i]:=bit[i]+x; inc(i,i and -i);
   end;
end;
function sum(i:longint):longint;
var s:longint;
begin
  s:=0;
  while i>0 do
   begin
     s:=s+bit[i]; dec(i,i and -i);
   end;
  exit(s);
end;
procedure qsort(l,r:longint; var a,u:arr);
var i,j,t,m:longint;
begin
  i:=l; j:=r; m:=a[(i+j) div 2];
  repeat
    while a[i]<m do inc(i);
    while m<a[j] do dec(j);
    if i<=j then
     begin
       t:=a[i]; a[i]:=a[j]; a[j]:=t;
       t:=u[i]; u[i]:=u[j]; u[j]:=t;
       inc(i);dec(j);
     end;
  until i>j;
  if i<r then qsort(i,r,a,u);
  if l<j then qsort(l,j,a,u);
end;
begin
  assign(input,‘match.in‘);
reset(input);
assign(output,‘match.out‘);
rewrite(output);
  readln(n);
  for i:=1 to n do begin read(a[i]);u[i]:=i; end;  readln;
  for i:=1 to n do begin read(b[i]);v[i]:=i; end;
   qsort(1,n,a,u); qsort(1,n,b,v);
  for i:=1 to n do
   begin
    a[i]:=i; b[v[i]]:=u[i];
   end;
  for i:=n downto 1 do
   begin
     inc(t,sum(b[i]));add(b[i],1);
   end;
  writeln(t mod 99999997);
  close(input); close(output);
end.

noip2014联合权值

题意很简单,不说了(其实是我懒得写)。

记录下每个点与之相邻所有点的权值和,权值平方和,最大值,次大值,所有点最大次大值乘积的最大值就是最大联合权值,权值和平方减权值平方和的和就是联合权值和。

代码:

program link;
var
  a,b,v,max1,max2,sum,num:array[0..200000]of int64;
  n,i:longint;  m,ans:int64;
begin
  assign(input,‘link.in‘);
reset(input);
assign(output,‘link.out‘);
rewrite(output);
  readln(n);
  for i:=1 to n-1 do
   readln(a[i],b[i]);
  for i:=1 to n do read(v[i]);
  for i:=1 to n-1 do
  begin
    if v[b[i]]>max1[a[i]] then begin max2[a[i]]:=max1[a[i]];max1[a[i]]:=v[b[i]]; end
      else if v[b[i]]>max2[a[i]] then max2[a[i]]:=v[b[i]];
    if v[a[i]]>max1[b[i]] then begin max2[b[i]]:=max1[b[i]];max1[b[i]]:=v[a[i]]; end
      else if v[a[i]]>max2[b[i]] then max2[b[i]]:=v[a[i]];
    inc(sum[a[i]],v[b[i]]); inc(num[a[i]],sqr(v[b[i]]));
    inc(sum[b[i]],v[a[i]]); inc(num[b[i]],sqr(v[a[i]]));
  end;
  for i:=1 to n do
   if max1[i]*max2[i]>m then m:=max1[i]*max2[i];
  for i:=1 to n do
  begin
    ans:=(ans+(sqr(sum[i])-num[i]) mod 10007) mod 10007;
  end;
  writeln(m,‘ ‘,ans);
  close(input); close(output);
end.

noip2014寻找道路

题意很简单不解释。

看清题意很重要,起点终点是由输入提供的,另外符合要求的点其所有出边指向的点与终点联通,无解输出-1.

做起来很简单,所有边反过来求一边终点到各点最短路径,判断每个点是否符合,然后在符合要求的点中求起点到终点最短路。

代码:

program road;
var
  c,a:array[0..10000,0..2000]of longint;
  q:array[0..500001]of longint;
  dis:array[0..10000]of longint;
  g,r:array[0..10000]of boolean;
  n,i,m,j,t,x,y,z,h,u,v:longint;
function min(x,y:longint):longint;
begin
  if x<y then min:=x else min:=y;
end;
begin
  assign(input,‘road.in‘);
  reset(input);
  assign(output,‘road.out‘);
  rewrite(output);
  readln(n,t);
  for i:=1 to t do
   begin
     readln(x,y);
     a[x,0]:=a[x,0]+1; a[x,a[x,0]]:=y;
     c[y,0]:=c[y,0]+1; c[y,c[y,0]]:=x;
   end; readln(x,y);
  for i:=1 to n do dis[i]:=maxlongint div 3;
  fillchar(g,sizeof(g),false);
  h:=0; t:=1; dis[y]:=0; q[1]:=y; g[y]:=true;
  while h<t do
   begin
     h:=h+1; u:=q[h]; g[u]:=false;
     for i:=1 to c[u,0] do
     begin
       v:=c[u,i];
       if dis[u]+1<dis[v] then
        begin
          dis[v]:=dis[u]+1;
          if g[v]=false then
            begin
              t:=t+1; q[t]:=v; g[v]:=true;
            end;
        end;
     end;
   end;
  for i:=1 to n do
   begin
     r[i]:=true;
    for j:=1 to a[i,0] do
     if dis[a[i,j]]>=maxlongint div 3 then begin r[i]:=false; break; end;
   end;
  for i:=1 to n do dis[i]:=maxlongint div 3;
  fillchar(g,sizeof(g),false);
  h:=0; t:=1; dis[x]:=0; q[1]:=x;  g[x]:=true;
  while h<t do
   begin
     h:=h+1; u:=q[h]; g[u]:=false;
     for i:=1 to a[u,0] do
     begin
       v:=a[u,i];
       if (dis[u]+1<dis[v])and(r[v]=true) then
        begin
          dis[v]:=dis[u]+1;
          if g[v]=false then
            begin
              t:=t+1; q[t]:=v; g[v]:=true;
            end;
        end;
     end;
   end; if (r[x]=false)or(dis[y]>=maxlongint div 3) then writeln(-1) else writeln(dis[y]);
  close(input); close(output);
end.

时间: 2024-10-14 16:59:16

NOIP试题解析的相关文章

Java中有关构造函数的一道笔试题解析

Java中有关构造函数的一道笔试题解析 1.具体题目如下 下列说法正确的有() A. class中的constructor不可省略 B. constructor必须与class同名,但方法不能与class同名 C. constructor在一个对象被new时执行 D.一个class只能定义一个constructor 2.解析说明 (1)class中的构造函数是可以省略的 /** * @Title:User.java * @Package:com.you.user.model * @Descrip

Javascript面试题解析

Javascript的一些面试题让很多同学感到头疼,下面就根据兄弟连教育(www.lampbrother.net)毕业学员面试遇到的面试题,给大家做一个简单的分享,希望对初入职场的你们有一些帮助:Javascript面试题解析. 第一题 /* 解析: + 优先级大于 ? 此题等价于: 'Value is true' ? 'Something' : 'Nothing' 所以结果是:'Something' */ var val = 'smtg'; console.log('Value is ' +

.NET面试题解析(04)-类型、方法与继承

  系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 做技术是清苦的.一个人,一台机器,相对无言,代码纷飞,bug无情.须梦里挑灯,冥思苦想,肝血暗耗,板凳坐穿.世界繁华竞逐,而你独钓寒江,看尽千山暮雪,听彻寒更雨歇.——来自<技术人的慰藉> 常见面试题目: 1. 所有类型都继承System.Object吗? 2. 解释virtual.sealed.override和abstract的区别 3. 接口和类有什么异同? 4. 抽象类和接口有什么区别?使用时

嵌入式linux面试题解析(二)——C语言部分二

嵌入式linux面试题解析(二)--C语言部分二 1..h头文件中的ifndef/define/endif 的作用?    答:防止该头文件被重复引用. 2.#include 与 #include "file.h"的区别?    答:前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h. 3.描述实时系统的基本特性    答 :在特定时间内完成特定的任务,实时性与可靠性. 4.全局变量和局部变量在内存中是否有区别?如果有,是

嵌入式linux面试题解析(一)——ARM部分二

嵌入式linux面试题解析(一)--ARM部分二 1.描述一下嵌入式基于ROM的运行方式基于RAM的运行方式有什么区别. 基于RAM的运行方式:需要把硬盘和其他介质的代码先加载到ram中,加载过程中一般有重定位的操作: 基于ROM:没有上面的操作. 基于ROM:速度较基于RAM的慢,因为会有一个把变量,部分代码等从存储器(硬盘,flash)搬移到RAM的过程:可用RAM资源比基于RAM的多: 基于RAM:速度较基于ROM的快,可用RAM比基于ROM的少,因为所有的代码,数据都必须存放在RAM中.

嵌入式linux面试题解析(三)——Linux应用编程部分一

嵌入式linux面试题解析(三)--Linux应用编程部分一 1.TCP与UDP的区别 TCP:是面向连接的流传输控制协议,具有高可靠性,确保传输数据的正确性,有验证重发机制,不会出现丢失或乱序. UDP:是无连接的数据报服务,不对数据报进行检查与修改,无须等待对方的应答,会出现分组丢失.重复.乱序,但具有较好的实时性,UDP段结构比TCP的段结构简单,因此网络开销也小. 2.流量控制和拥塞控制 拥塞控制    网络拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致

嵌入式linux面试题解析(二)——C语言部分三

嵌入式linux面试题解析(二)--C语言部分三 1.下面的程序会出现什么结果#include <stdio.h>#include <stdlib.h> #include <string.h>void getmemory(char *p){    p=(char *) malloc(100);    strcpy(p,"hello world");}int main( ){    char *str=NULL;    getmemory(str); 

.NET面试题解析(07)-多线程编程与线程同步

系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等,本文只是从常见面试题的角度(也是开发过程中常用)去深入浅出线程相关的知识.如果想要系统的学习多线程,没有捷径的,也不要偷懒,还是去看专业书籍的比较好. 常见面试题目: 1. 描述线程与进程的区别? 2. 为什么GUI不支持跨线程访问控件?一般如何解决这个问题? 3. 简述后台线程和前台线程的区别? 4. 说说常

.NET面试题解析(07)-SQL语言基础及数据库基本原理

  系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 本文内容涉及到基本SQL语法,数据的基本存储原理,数据库一些概念.数据优化等.抱砖引玉,权当一个综合复习! 常见面试题目: 0. 基本SQL语法题目,在 正文“基础SQL语法”中有13道题,这里就略过了. 1. 索引的作用?她的优点缺点是什么? 2. 介绍存储过程基本概念和 她的优缺点? 3. 使用索引有哪些需要注意的地方? 4. 索引碎片是如何产生的?有什么危害?又该如何处理? 5. 锁的目的是什么? 6.