NOIP 2010 题解

【前言】最近这的很少弄OI了,虽说是暑假。趁要把NOIP2010~2013的题刷完,我做完一份便写一篇题解吧。

【P1774机器翻译】

P1774机器翻译

Accepted

标签:[显示标签]

描述

小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。

这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果内存中有,软件就会用它进行翻译;如果内存中没有,软件就会在外存中的词典内查找,查出单词的中文含义然后翻译,并将这个单词和译义放入内存,以备后续的查找和翻译。

假设内存中有M个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过M-1,软件会将新单词存入一个未使用的内存单元;若内存中已存入M个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。

假设一篇英语文章的长度为N个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。

格式

输入格式

输入文件共2行。每行中两个数之间用一个空格隔开。

第一行为两个正整数M和N,代表内存容量和文章的长度。

第二行为N个非负整数,按照文章的顺序,每个数(大小不超过1000)代表一个英文单词。文章中两个单词是同一个单词,当且仅当它们对应的非负整数相同。

输出格式

包含一个整数,为软件需要查词典的次数。

样例1

样例输入1[复制]

3 7
1 2 1 5 4 4 1

样例输出1[复制]

5

限制

每个测试点1s

提示

对于10%的数据有M=1,N≤5。

对于100%的数据有0<=N<=100,0<=M<=1000。

整个查字典过程如下:每行表示一个单词的翻译,冒号前为本次翻译后的内存状况:

空:内存初始状态为空。

1. 1:查找单词1并调入内存。

2. 1 2:查找单词2并调入内存。

3. 1 2:在内存中找到单词1。

4. 1 2 5:查找单词5并调入内存。

5. 2 5 4:查找单词4并调入内存替代单词1。

6. 2 5 4:在内存中找到单词4。

7. 5 4 1:查找单词1并调入内存替代单词2。

共计查了5次词典。

来源

noip2010提高组复赛

【分析】这大概是纯模拟吧。看样子有点想缓存交换,但是直接暴力即可,甚至连map也不用开。

【代码】

#include<cstdio>
#define N 100005
using namespace std;
int now[N],T[N],ans,m,n,h,t,i,x;
int main()
{
  scanf("%d%d",&m,&n);
  h=1;t=0;
  for (i=1;i<=n;i++)
  {
    scanf("%d",&x);
    if (T[x]) continue;ans++;
    if (t<m) {now[++t]=x;T[x]=1;continue;}
    T[now[h++]]=0;T[now[++t]=x]=1;
  }
  printf("%d",ans);
  return 0;
}

【P1775乌龟棋】

P1775乌龟棋

Accepted

标签:[显示标签]

描述

小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。

乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数)。棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

乌龟棋中M张爬行卡片,分成4种不同的类型(M张卡片中不一定包含所有4种类型的卡片,见样例),每种类型的卡片上分别标有1、2、3、4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

格式

输入格式

输入文件的每行中两个数之间用一个空格隔开。

第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。

第2行N个非负整数,a1a2……aN,其中ai表示棋盘第i个格子上的分数。

第3行M个整数,b1b2……bM,表示M张爬行卡片上的数字。

输入数据保证到达终点时刚好用光M张爬行卡片。

输出格式

输出只有1行,1个整数,表示小明最多能得到的分数。

样例1

样例输入1[复制]

9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1

样例输出1[复制]

73

限制

每个测试点1s

提示

小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,由于起点是1,所以自动获得第1格的分数6。

对于30%的数据有1≤N≤30,1≤M≤12。

对于50%的数据有1≤N≤120,1≤M≤50,且4种爬行卡片,每种卡片的张数不会超过20。

对于100%的数据有1≤N≤350,1≤M≤120,且4种爬行卡片,每种卡片的张数不会超过40;0≤ai≤100,1≤i≤N;1≤bi≤4,1≤i≤M。

来源

noip2010提高组复赛

【分析】显然是DP。开始觉得有点难以下手,后来发现卡片只有4种,每种也不多。那么我们可以暴力把每种卡片用了几张当做下标来DP。以为四种卡片用了几张知道后,总路程也知道了,所以只要四维即可。效率是40^4。

【代码】

#include<cstdio>
#include<cstring>
#define N 505
#define C 45
using namespace std;
int f[C][C][C][C],ord[N],d[5];
int P,i,j,k,l,n,m,x;
inline void up(int &x,int add)
{
  int now=P;
  if ((now+=add)>n) return;
  if (f[i][j][k][l]+ord[now]>x) x=f[i][j][k][l]+ord[now];
}
int main()
{
  scanf("%d%d",&n,&m);
  for (i=1;i<=n;i++) scanf("%d",&ord[i]);
  for (i=1;i<=m;i++)
    scanf("%d",&x),d[x]++;
  memset(f,-1,sizeof(f));
  f[0][0][0][0]=ord[1];
  for (i=0;i<=d[1];i++)
    for (j=0;j<=d[2];j++)
      for (k=0;k<=d[3];k++)
        for (l=0;l<=d[4];l++)
        {
          if (f[i][j][k][l]==-1) continue;P=i+j*2+k*3+l*4+1;
          if (i<d[1]) up(f[i+1][j][k][l],1);
          if (j<d[2]) up(f[i][j+1][k][l],2);
          if (k<d[3]) up(f[i][j][k+1][l],3);
          if (l<d[4]) up(f[i][j][k][l+1],4);
        }
  printf("%d",f[d[1]][d[2]][d[3]][d[4]]);
  return 0;
}

【P1776关押罪犯】

P1776关押罪犯

Accepted

标签:[显示标签]

描述

S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c的冲突事件。每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S城Z市长那里。公务繁忙的Z市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。在详细考察了N名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使Z市长看到的那个冲突事件的影响力最小?这个最小值是多少?

格式

输入格式

输入文件的每行中两个数之间用一个空格隔开。

第一行为两个正整数N和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的M行每行为三个正整数aj,bj,cj,表示aj号和bj号罪犯之间存在仇恨,其怨气值为cj。

数据保证1<=aj<=bj<=N,0<=cj<=1000000000,且每对罪犯组合只出现一次。

输出格式

输出文件共1行,为Z市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出0。

样例1

样例输入1[复制]

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

样例输出1[复制]

3512

限制

每个测试点1s

提示

分配方法:市长看到的冲突事件影响力是3512(由2号和3号罪犯引发)。其他任何分法都不会比这个分法更优。

对于30%的数据有N≤15。

对于70%的数据有N≤2000,M≤50000。

对于100%的数据有N≤20000,M≤100000。

来源

noip2010提高组复赛

【分析】开始看着标签是二分图,心下有点紧张:提高组考这个?结果看完题目觉得是水水的并查集。

有点想食物链?

先是贪心思想。我们按争吵值从大到小排序,每次显然要当前的尽量符合,若不符合就直接输答案。

维护的话用并查集。可以拆点,也可以不拆点用dis来维护到父亲的距离(0或1)。

【代码】

#include<cstdio>
#include<algorithm>
#define N 200005
using namespace std;
struct prisoner
{
  int x,y,z;
  friend inline int operator < (const prisoner &a,const prisoner &b){return a.z>b.z;}
}a[N];
int f[N],d[N],n,m,i,x,y,u,v;
inline int get(int u)
{
  if (f[u]==u) return u;
  int fa=get(f[u]);
  (d[u]+=d[f[u]])&=1;
  return f[u]=fa;
}
int main()
{
  scanf("%d%d",&n,&m);
  for (i=1;i<=m;i++)
    scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
  sort(a+1,a+m+1);
  for (i=1;i<=n;i++) f[i]=i;
  for (i=1;i<=m;i++)
  {
    x=a[i].x;y=a[i].y;
    u=get(x);v=get(y);
    if (u!=v) f[v]=u,d[v]=(d[x]==d[y]);
    else if (d[x]==d[y]) {printf("%d",a[i].z);return 0;}
  }
  puts("0");
  return 0;
}

【P1777引水入城】

P1777引水入城

Accepted

标签:[显示标签]

描述

在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N行M列的矩形,其中每个格子都代表一座城市,每座城市都有一个海拔高度。

为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。

由于第N行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

格式

输入格式

输入文件的每行中两个数之间用一个空格隔开。

输入的第一行是两个正整数N和M,表示矩形的规模。

接下来N行,每行M个正整数,依次代表每座城市的海拔高度。

输出格式

输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。

样例1

样例输入1[复制]

2 5
9 1 5 4 3
8 7 6 1 2

样例输出1[复制]

1
1

限制

每个测试点1s

提示

本题共有10个测试数据,每个数据的范围如下表所示:

测试数据编号 能否满足要求 N M

1 不能 ≤ 10 ≤ 10

2 不能 ≤ 100 ≤ 100

3 不能 ≤ 500 ≤ 500

4 能 = 1 ≤ 10

5 能 ≤ 10 ≤ 10

6 能 ≤ 100 ≤ 20

7 能 ≤ 100 ≤ 50

8 能 ≤ 100 ≤ 100

9 能 ≤ 200 ≤ 200

10 能 ≤ 500 ≤ 500

对于所有的10个数据,每座城市的海拔高度都不超过10^6。

来源

noip2010提高组复赛

【分析】这道题有点神啊。后来一想也是可做的。

对于不能,直接把第一排全部当成蓄水池,然后DFS或BFS判断最后一排即可。

对于能,有点棘手。首先有一个结论:第一排的某个点如果装了蓄水池,它影响的最后一排的点一定是连续的。(证明见下)那么我们先用N^2的效率求出第一排的每个点影响的区域L[i]和R[i]。至于求法,我是用记忆化搜索的。之后可以用DP或者贪心,问题转化成了:给定M个区间,求覆盖1~M最少需要几个线段。

【简要证明】

设点X影响的范围是(L1,R1)和(L2,R2),且R1<L2,即有一段空出来的(R1+1,R2-1)

因为是能,一定存在一个第一排的点Y是影响R1+1~R2-1这一段的某一个或几个城市。

那么X和Y到下面的路径一定会交叉。既然是交叉,X也能到Y的地方去。

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 505
using namespace std;
struct Room{int L,R;}g[N][N],H[N];
int x[N*N],y[N*N],f[N][N],a[N][N];
int n,m,i,j,NO,now,ans,last;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
inline void Bfs()
{
  int h=0,t=m;
  for (int i=1;i<=m;i++)
    x[i]=1,y[i]=i,f[1][i]=1;
  while (h<t)
  {
    int X=x[++h],Y=y[h];
    for (int i=0;i<4;i++)
    {
      int xx=X+dx[i],yy=Y+dy[i];
      if (xx<1||xx>n||yy<1||yy>m||f[xx][yy]||a[X][Y]<=a[xx][yy]) continue;
      x[++t]=xx;y[t]=yy;f[xx][yy]=1;
    }
  }
  for (int i=1;i<=m;i++) if (!f[n][i]) NO++;
}
Room Fill(int X,int Y)
{
  if (f[X][Y]) return g[X][Y];
  g[X][Y].L=(X==n)?Y:m+1;g[X][Y].R=(X==n)?Y:0;f[X][Y]=1;
  for (int i=0;i<4;i++)
  {
    int xx=X+dx[i],yy=Y+dy[i];
    if (xx<1||xx>n||yy<1||yy>m||a[X][Y]<=a[xx][yy]) continue;
    Room temp=Fill(xx,yy);
    g[X][Y].L=min(g[X][Y].L,temp.L);
    g[X][Y].R=max(g[X][Y].R,temp.R);
  }
  return g[X][Y];
}
inline int cmp(const Room &a,const Room &b)
{
  if (!a.R||!b.R) return a.R;
  return a.L<b.L||a.L==b.L&&a.R>b.R;
}
int main()
{
  scanf("%d%d",&n,&m);
  for (i=1;i<=n;i++)
    for (j=1;j<=m;j++)
      scanf("%d",&a[i][j]);
  Bfs();
  if (!NO) puts("1");
  else {puts("0");printf("%d",NO);return 0;}
  memset(f,0,sizeof(f));
  for (now=1;now<=m;now++)
    H[now]=Fill(1,now);
  sort(H+1,H+m+1,cmp);
  ans=0;now=0;last=1;
  for (i=1;i<=m&&H[i].R&&last<m;i++)
  {
    if (H[i].L<=last+1) {now=max(now,H[i].R);continue;}
    last=now;now=H[i].R;ans++;
  }
  if (last!=m) ans++;
  printf("%d",ans);
  return 0;
}

NOIP 2010 题解

时间: 2024-10-30 04:48:56

NOIP 2010 题解的相关文章

NOIP 2010题解

唔..NOIP2010比较简单,总体感觉不错. Problem 1: 机器翻译 水题,队列的简单应用. 读入时判断是否在内存中,可以用hash优化.如果不在内存中push进内存,放不下了pop header不用说了.上代码(未hash优化) //Bazinga! #include "cstdio" int sum,i,m,n; struct Q{ int len,head,tail,qub[1001],i; void push(int n){ qub[tail]=n; ++tail;

NOIP 2012 题解

[D1T1vigenere密码] P1778vigenere密码 Accepted 标签:[显示标签] 描述 16世纪法国外交家Blaise de Vigenère设计了一种多表密码加密算法--Vigenère密码.Vigenère密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用M表示:称加密后的信息为密文,用C表示:而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为k. 在Vigenère

洛谷 P1525 关押罪犯==codevs 1069 关押罪犯[NOIP 2010]

P1525 关押罪犯 513通过 1.4K提交 题目提供者该用户不存在 标签图论并查集NOIp提高组2010 难度普及+/提高 提交该题 讨论 题解 记录 最新讨论 咳咳.竟MLE了. 囧.运行时错误,错误编号-… 点2是何方神圣? 题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多.

【noip 2010】 关押罪犯

描述 S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多.如果两名怨气值为c的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c的冲突事件.每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S城Z市长那里.公务繁忙的Z市长只会去看列表中的第一个

NOIP 2014 题解

好吧,15年写14年题解,的确够晚的(P.S. 是因为我到现在才搞懂这些题) 正文之前,先膜拜膜拜一位大爷 %%% _debug 多膜拜膜拜 _debug 大爷,打程序时bug会减少哦 传送门: 生活大爆炸版石头剪刀布: http://codevs.cn/problem/3716/ 联合权值: http://codevs.cn/problem/3728/ 飞扬的小鸟: http://codevs.cn/problem/3729/ 无线网络发射器选址: http://codevs.cn/probl

历年NOIP选题题解汇总

联赛前上vijos板刷往年联赛题,使用在线编辑编写代码,祝我rp++. 废话不多说,挑比较有意思的记一下. 题目是按照年份排序的,最早只到了03年. 有些题目因为 我还没写/很早之前写的忘了 所以就先没写题解. NOIP2003 神经网络:按照题目怎么说怎么做,BFS即可.注意输出层是指出度为0的层,不是指深度最大的. 传染病防治:爆搜题,枚举每一层减掉哪个.复杂度不可算,大概在O(2^20*8!)强势不满,貌似卡不掉. NOIP2004 虫食算:知二推三,边搜边判. NOIP2005 过河:把

noip 2010 引水入城(dfs + 贪心)

非常感到抱歉,由于昨天有点忙,这道题的题解没写,今天补上,争取写的更加详细一点,让大家明白. 看一下题意: 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个NNN 行×M \times M×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施.水利设施有两种,分别为蓄水厂和输水站.蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中. 因此,

noip 2010 三国游戏

三国游戏 三国游戏 描述 小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏. 在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有N 位武将(N为偶数且不小于4),任意两个武将之间有一个"默契值",表示若此两位武将作为一对组合作战时,该组合的威力有多大.游戏开始前,所有武将都是自由的(称为自由武将,一旦某个自由武将被选中作为某方军队的一员,那么他就不再是自由武将了),换句话说,所谓的自由武将不属于任何一方.游戏开始,小涵和计算机要从自由武将中挑选武将组

noip 2010 关押罪犯 (二分图染色 并茶几)

/* 二分图染色版本 两个监狱对应二部图的两部分 在给定的怨气值里二分 对于每一个Ci 进行染色判断是否合法 染色的时候 如果这条边的ci > Ci 这两个人就带分开 即染成不同的颜色 如果染色到某两个点颜色相同且怨气值>Ci 这个Ci就不合法 二分直到最后答案 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100