noip2010题解
描述
小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。
这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果内存中有,软件就会用它进行翻译;如果内存中没有,软件就会在外存中的词典内查找,查出单词的中文含义然后翻译,并将这个单词和译义放入内存,以备后续的查找和翻译。
假设内存中有M个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过M-1,软件会将新单词存入一个未使用的内存单元;若内存中已存入M个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。
假设一篇英语文章的长度为N个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。
格式
输入格式
输入文件共2行。每行中两个数之间用一个空格隔开。
第一行为两个正整数M和N,代表内存容量和文章的长度。
第二行为N个非负整数,按照文章的顺序,每个数(大小不超过1000)代表一个英文单词。文章中两个单词是同一个单词,当且仅当它们对应的非负整数相同。
输出格式
包含一个整数,为软件需要查词典的次数。
限制
每个测试点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次词典。
1 #include<stdio.h> 2 #include<iostream> 3 #include<cstdlib> 4 int m,N,input[1005]={0}; 5 6 class Queue 7 { 8 public: 9 Queue(){} 10 ~Queue(){} 11 int getrear(){return rear;} 12 int getfront(){return front;} 13 int getsize(){return size;} 14 int getnumber(){return number;} 15 void setfront(int x){front=x;} 16 void setrear(int x){rear=x;} 17 void setsize(int x){size=x;} 18 int getqueue(int i){return queue[i];} 19 void Cleanqueue(int x) 20 { 21 for(int i=0;i<=1005;i++) 22 queue[i]=-1; 23 number=0; 24 M=x; 25 } 26 int Checkqueue(int x) 27 { 28 for(int i=0;i<=1005;i++) 29 if(queue[i]==x)return 0; 30 Enqueue(x); 31 return 1; 32 } 33 void Enqueue(int x) 34 { 35 if(size==M)Dequeue(); 36 queue[rear]=x; 37 number++; 38 size++; 39 rear++; 40 if(rear==1005)rear=0; 41 } 42 int Dequeue() 43 { 44 int x=queue[front]; 45 queue[front]=-1; 46 size--; 47 front++; 48 return x; 49 } 50 private: 51 int queue[1006]; 52 int size,rear,front,M,number; 53 }; 54 55 int main() 56 { 57 std::cin>>m>>N; 58 for(int i=0;i<N;i++) 59 std::cin>>input[i]; 60 Queue a; 61 a.setfront(0); 62 a.setsize(0); 63 a.setrear(0); 64 a.Cleanqueue(m); 65 for(int i=0;i<N;i++) 66 a.Checkqueue(input[i]); 67 std::cout<<a.getnumber(); 68 std::cout<<std::endl; 69 system("pause"); 70 return 0; 71 }
描述
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行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个整数,表示小明最多能得到的分数。
限制
每个测试点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。
dp
1 #include<stdio.h> 2 #include<iostream> 3 #include<cstdlib> 4 int ans[42][42][42][42]={0},step[355]={0}; 5 int anum=0,bnum=0,cnum=0,dnum=0,N,M; 6 7 int max(int a,int b) 8 { 9 if(a>b)return a; 10 return b; 11 } 12 13 int main() 14 { 15 int x; 16 std::cin>>N>>M; 17 for(int i=0;i<N;i++) 18 std::cin>>step[i]; 19 ans[0][0][0][0]=step[0]; 20 for(int i=0;i<M;i++) 21 { 22 std::cin>>x; 23 if(x==1)anum++; 24 if(x==2)bnum++; 25 if(x==3)cnum++; 26 if(x==4)dnum++; 27 } 28 for(int a=0;a<=anum;a++) 29 for(int b=0;b<=bnum;b++) 30 for(int c=0;c<=cnum;c++) 31 for(int d=0;d<=dnum;d++) 32 { 33 if(a==0&&b==0&&c==0&&d==0)continue; 34 int maxa=0,maxb=0,maxc=0,maxd=0; 35 if(a>=1)maxa=ans[a-1][b][c][d]+step[a+b*2+c*3+d*4]; 36 if(b>=1)maxb=ans[a][b-1][c][d]+step[a+b*2+c*3+d*4]; 37 if(c>=1)maxc=ans[a][b][c-1][d]+step[a+b*2+c*3+d*4]; 38 if(d>=1)maxd=ans[a][b][c][d-1]+step[a+b*2+c*3+d*4]; 39 ans[a][b][c][d]=max(max(maxa,maxb),max(maxc,maxd)); 40 } 41 std::cout<<ans[anum][bnum][cnum][dnum]<<std::endl; 42 return 0; 43 }
描述
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。
限制
每个测试点1s
提示
分配方法:市长看到的冲突事件影响力是3512(由2号和3号罪犯引发)。其他任何分法都不会比这个分法更优。
对于30%的数据有N≤15。
对于70%的数据有N≤2000,M≤50000。
对于100%的数据有N≤20000,M≤100000。
并查集+贪心
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 using namespace std; 6 int number[40005],m,n,value[100005][3]; 7 8 int Find(int x) 9 { 10 if(number[x]==x) 11 return number[x]; 12 else 13 return number[x]=Find(number[x]); 14 } 15 16 int devide(int l, int r) 17 { 18 int x=value[(l+r)/2][2],i=l-1,j=r+1; 19 while(1) 20 { 21 do{--j;} 22 while(value[j][2]>x); 23 24 do{++i;} 25 while(value[i][2]<x); 26 27 if(i<j) 28 { 29 int t=value[i][0]; 30 value[i][0]=value[j][0]; 31 value[j][0]=t; 32 t=value[i][1]; 33 value[i][1]=value[j][1]; 34 value[j][1]=t; 35 t=value[i][2]; 36 value[i][2]=value[j][2]; 37 value[j][2]=t; 38 } 39 else return j; 40 } 41 } 42 43 void qsort(int l,int r) 44 { 45 int p; 46 if(l<r) 47 { 48 p=devide(l,r); 49 qsort(l,p); 50 qsort(p+1,r); 51 } 52 } 53 54 int main() 55 { 56 cin>>n>>m; 57 for(int i=0;i<m;i++) 58 scanf("%d%d%d",&value[i][0],&value[i][1],&value[i][2]); 59 qsort(0,m-1); 60 for(int i=0;i<n*2;i++) 61 number[i]=i; 62 63 for(int i=m-1;i>=0;i--) 64 { 65 int x=Find(value[i][0]),y=Find(value[i][1]),a=Find(value[i][0]+n),b=Find(value[i][1]+n); 66 67 if(x==y) 68 { 69 cout<<value[i][2]<<endl; 70 return 0; 71 } 72 73 number[x]=b; 74 number[y]=a; 75 } 76 77 cout<<"0"<<endl; 78 return 0; 79 }
描述
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N行M列的矩形,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。因此,只有与湖泊毗邻的第1行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。
由于第N行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。
格式
输入格式
输入文件的每行中两个数之间用一个空格隔开。
输入的第一行是两个正整数N和M,表示矩形的规模。
接下来N行,每行M个正整数,依次代表每座城市的海拔高度。
输出格式
输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。
限制
每个测试点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。
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<cstdlib> 5 #include<algorithm> 6 #define N 505 7 using namespace std; 8 int n,m; 9 int map[N][N]; 10 int flag[N][N]; 11 int number[N]; 12 13 struct object 14 { 15 int a,b; 16 }; 17 18 class Queue 19 { 20 private: 21 int front,rear,size; 22 object queue[N*N]; 23 public: 24 Queue() 25 { 26 front=size=0; 27 rear=-1; 28 } 29 object Dequeue() 30 { 31 object x=queue[front]; 32 front++; 33 if(front==N*N) 34 front=0; 35 size--; 36 return x; 37 } 38 void Enqueue(int a,int b) 39 { 40 rear++; 41 if(rear==N*N) 42 rear=0; 43 queue[rear].a=a; 44 queue[rear].b=b; 45 size++; 46 } 47 void Enqueue(object x) 48 { 49 rear++; 50 if(rear==N*N) 51 rear=0; 52 queue[rear]=x; 53 size++; 54 } 55 int Getsize() 56 { 57 return size; 58 } 59 }mq; 60 61 void BFS(int a) 62 { 63 object thi; 64 thi.a=0; 65 thi.b=a; 66 mq.Enqueue(thi); 67 flag[thi.a][thi.b]=a; 68 while(mq.Getsize()) 69 { 70 object now=mq.Dequeue(); 71 if(now.a!=0&&flag[now.a-1][now.b]!=a&&map[now.a-1][now.b]<map[now.a][now.b]) 72 { 73 flag[now.a-1][now.b]=a; 74 mq.Enqueue(now.a-1,now.b); 75 } 76 if(now.b!=0&&flag[now.a][now.b-1]!=a&&map[now.a][now.b-1]<map[now.a][now.b]) 77 { 78 flag[now.a][now.b-1]=a; 79 mq.Enqueue(now.a,now.b-1); 80 } 81 if(now.a!=n-1&&flag[now.a+1][now.b]!=a&&map[now.a+1][now.b]<map[now.a][now.b]) 82 { 83 flag[now.a+1][now.b]=a; 84 mq.Enqueue(now.a+1,now.b); 85 } 86 if(now.b!=m-1&&flag[now.a][now.b+1]!=a&&map[now.a][now.b+1]<map[now.a][now.b]) 87 { 88 flag[now.a][now.b+1]=a; 89 mq.Enqueue(now.a,now.b+1); 90 } 91 } 92 int mark=-1; 93 for(int i=0;i<m;i++) 94 if(flag[n-1][i]==a) 95 { 96 mark=i; 97 break; 98 } 99 if(mark==-1) 100 return ; 101 for(int i=m-1;i>=0;i--) 102 if(flag[n-1][i]==a) 103 { 104 number[mark]=max(number[mark],i); 105 break; 106 } 107 } 108 109 int main() 110 { 111 scanf("%d%d",&n,&m); 112 for(int i=0;i<n;i++) 113 for(int j=0;j<m;j++) 114 scanf("%d",&map[i][j]); 115 for(int i=0;i<n;i++) 116 for(int j=0;j<m;j++) 117 flag[i][j]=-1; 118 for(int i=0;i<m;i++) 119 BFS(i); 120 int cnt=0; 121 for(int j=0;j<m;j++) 122 if(flag[n-1][j]==-1) 123 cnt++; 124 if(cnt!=0) 125 { 126 printf("0\n"); 127 printf("%d\n",cnt); 128 return 0; 129 } 130 int l=0,r=0,ans=0; 131 while(r!=m-1) 132 { 133 int nowmax=0; 134 for(int i=0;i<=r+1;i++) 135 nowmax=max(nowmax,number[i]); 136 r=nowmax; 137 ans++; 138 } 139 printf("1\n%d\n",ans); 140 return 0; 141 }