题目名称 | 数字查找 | 开发计划 | 魅力花园 | 百进制数 |
输入文件 | find.in | plan.in | park.in | hex.in |
输出文件 | find.out | plan.out | park.out | hex.out |
测试点数目 | 10 | 10 | 10 | 10 |
测试点分数 | 10 | 10 | 10 | 10 |
题目类型 | 传统 | 传统 | 传统 | 传统 |
时间限制 | 1s | 1s | 1s | 1s |
空间限制 | 128MB | 128MB | 128MB | 128MB |
NOIP2011模拟题
1. 数字查找
(find.pas/c/cpp)
【题目描述】
X和Y在玩一个非常有意思的游戏,X在纸上写了n个数字,然后X向Y提一些问题,Y来回答。
“你知道这些数字中两两结合组成的和不超过M1的有多少种吗?”
“这太简单了!有K1种!”
“你知道这些数字中两两结合组成的和不超过M2的有多少种吗?”
“这太简单了!有K2种!”
“你知道这些数字中两两结合组成的和不超过M3的有多少种吗?”
“这太简单了!有K3种!”
“你知道……”
“烦不烦!不知道!”
就这样,Y怒了。
但是Y仔细一想,不能和X一般见识,但是又不愿意回答如此单调的问题。所以Y请你来帮忙。
【输入格式】
第一行一个数n,表示数字的个数;
第二行到第n+1行,每行一个不超过2,000,000,000的数k;
第n+2行一个数m,表示m个问题;
第n+3行到第n+m+2行,每行一个数M,询问表示n中两两组合不超过M的组合的个数;
【输出格式】
输出m行,每行对应一个答案
【输入样例】
3
1
2
3
2
2
3
【输出样例】
0
1
【数据范围】
30%的数据1<=n<=100,1<=m<=50,k<=2000;
100%的数据 1<=n<=10000, 1<=m<=100,k<=2,000,000,000;
#include <cstdio> #include <algorithm> using namespace std; long long a[110000]; int n,m; long long x; int find(long long x){ int tot=0; int r=n-1; for (int i=0;i<n;i++){ while (r>i && a[i]+a[r]>x) r--; if (i==r) return tot; tot+=r-i; } return tot; } int main(){ freopen("find.in","r",stdin); freopen("find.out","w",stdout); scanf("%d",&n); for (int i=0;i<n;i++){ scanf("%I64d",&a[i]); } sort(a,a+n); scanf("%d",&m); for (int i=1;i<=m;i++){ scanf("%I64d",&x); int ans=find(x); printf("%d\n",ans); } return 0; }
2. 开发计划
(plan.pas/c/cpp)
【问题描述】
DD战队的首领DDS最近几天很烦恼,DD战队想要继续开发新小陆,DDS必须马上制定出开发计划。新小陆可开发区域位于一片沼泽地中,数目不明,DD战队可以随便选择一个进行开发。DDS已经得到了前往沼泽地的地图,他可以清晰地看到自己所在的总部位于1号已开发区域,并且知道由1号已开发区域可以到达的每一片区域以及这些可以到达的区域可以到达的区域。这些区域包括已开发的和未开发(可开发)的,共有n个,每一个区域都有一个固定编号,从1~n;而且整个新小陆刚好有n-1条路径。由一个区域到达另一个区域需要一天,并且到达这个新的区域后不会再返回。
虽然不知道新小陆可开发区域的具体位置,但是DDS知道它们有共同的特征:一旦进入将无路可走,即没有新的区域可以到达。有的区域比较贫瘠,称之为P区域,在P区域会因为各种问题不得不逗留一天,然后才能继续前进;假如可开发区域也是P区域,那么逗留几天显然不是问题,P可开发区域和其他可开发区域等价。
知道这些并不能完全解决DDS的烦恼,由于DD战队的成员智商很低,到达一个区域后不知道权衡利弊,总是随便选择一个新的可以到达的区域前进,所以他们可能走了很久才到达一个可开发区域。
DD战队当然想尽量节省物资,所以战队只能提供足够m天使用的物资。DDS想知道他的队员们最不可能到达和最可能到达的可开发区域的编号,假如有多个地区情况类似,两个答案都输出编号最小的。
【输入格式】
第一行三个数,n,m,k。分别表示区域数目,物资可以承受的天数和P区域的数目;
第二行k个数(若k<>0),表示P区域的编号;
接下来n-1行,每行两个数表示相连的区域的编号。
【输出格式】
输出两行,第一行表示最不可能到达的可开发区域,第二行表示最可能到达的可开发区域。
【输入样例】
6 1 0
1 2
1 3
2 4
2 6
4 5
【输出样例】
5
3
【数据范围】
20%数据:2<=n<=20 , 2<=m<=50 , 0<=k<=5
100%数据:2<=n<=1000, 2<=m<=1000; 0<=k<=100
【Hint】
物资可以剩余。
#include <cstdio> #define MAXN 1001 int n,m,k; int a[MAXN][MAXN]; int b[MAXN][MAXN]; bool p[MAXN]; bool v[MAXN]; double f[MAXN][MAXN]; int ans1,ans2; void make(int x){ v[x]=true; for (int i=1;i<=n;i++){ if (a[x][i] && !v[i]){ b[x][++b[x][0]]=i; make(i); } } } int main(){ freopen("plan.in","r",stdin); freopen("plan.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=k;i++){ int x; scanf("%d",&x); p[x]=true; } for (int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); a[x][y]=true; a[y][x]=true; } make(1); f[1][0]=1; for (int j=0;j<=m;j++){ for (int i=1;i<=n;i++){ for (int k=1;k<=b[i][0];k++){ int t=b[i][k]; if (p[t]) f[t][j+2]+=f[i][j]/(double)b[i][0]; else f[t][j+1]+=f[i][j]/(double)b[i][0]; } } } double max=0,min=10000; for (int i=2;i<=n;i++){ double tot=0; if (b[i][0]==0){ for (int j=1;j<=m;j++){ tot+=f[i][j]; } if (tot>max){ max=tot; ans1=i; } if (tot<min){ min=tot; ans2=i; } } } printf("%d\n%d\n",ans2,ans1); return 0; }
3. 魅力花园
(park.pas/c/cpp)
【问题描述】
在城市里会有很多花园,我们如何判断某一个花园是不是魅力花园呢?不同的人有不同的要求,而且花园对于不同的人的要求的敏感程度不同。比如市长的要求要比市民的要求有用的多,城管的要求又高于市长的要求。花园的园长很为难。他必须让尽可能多的人都感到满意。
假设有n个群体对花园提出了n个要求,每个群体的要求不同,园长根据要求被提出的时间先后和要求的价值大小进行选择性的满足。园长只会对时间早的和价值高的要求进行满足。例如两个要求A和B的提出时间分别是a,b(a<b),价值分别是a',b'(a'>b'),那么他们可以同时被满足。
园长为了打造魅力花园,当然希望满足尽可能多的不同群体的要求。他想让你帮他设计一个规划,计算出最多能满足多少个群体的要求。
【输入格式】
第一行一个n,表示有n个群体;
第二行n个整数,n个群体的问题的时间由早到晚排序后的标号顺序;
第三行n个整数,n个群体的问题的价值从大到小排序后的标号顺序;
【输出格式】
一个数表示最多能满足的要求数;
【输入样例】
5
1 3 4 5 6
6 5 3 4 1
【输出样例】
2
【数据范围】
30%的数据:1<=n<=1000;
100%的数据:1<=n<=100000;
#include <cstdio> #include <algorithm> using namespace std; int n; int a[100010]; int b[100010]; int p[100010]; int q[100010]; int tail; int find(int x){ if (q[tail]>=x){ tail++; return tail; } int l=1,r=tail; while (l<r){ int mid=(l+r) >> 1; if (q[mid]>=x) l=mid+1;else r=mid; } return l; } int main(){ freopen("park.in","r",stdin); freopen("park.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); } for (int i=1;i<=n;i++){ int x; scanf("%d",&x); p[x]=n-i+1; } for (int i=1;i<=n;i++) b[i]=p[a[i]]; for (int i=1;i<=n;i++){ if (tail==0){ q[++tail]=b[i]; continue; } int j=find(b[i]); q[j]=b[i]; } printf("%d\n",tail); return 0; }
4. 百进制数
(hex.pas/c/cpp)
【问题描述】
科学进步飞快,日新月异,人们早已经不再习惯十进制那种单调的表示数字的方式。最近,Y同学投入百进制数的研究中。两个百进制数可以相邻当且仅当前一个百进制数的最后一位和后一个百进制数的第一位相同,这一位数字称之为一个交点,每一位数字最多能以起点和终点的角色属于交点一次(例如1234—3434—3412,是非法序列,因为34以起点和终点的角色充当交点各两次)。任意一个百进制数或多个可以相邻的百进制数可以形成一个合法序列。一个完美序列满足序列中所有的百进制数长度之和是所有合法序列中最大的。给出n个百进制数,我们希望将其排列才能组成最长的百进制数完美序列。
【输入格式】
第一行一个数n表示百进制数的个数;
第二行到第n-1行每行一个长度为L的百进制数。
【输出格式】
输出完美序列的长度。
【输入样例】
5
1234
347891
1291
9988
9156
【输出样例】
14
【数据范围】
20%的数据:1<=n<=10, 1<=L<=10;
80%的数据:1<=n<=50, 1<=L<=100;
100%的数据:1<=n<=100,1<=L<=100;
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; int n; char s[1000]; struct edge{ int x,w,next; }e[10000]; int tot; int k[1000]; int ans; bool vst[101],ven[101]; bool v[101]; bool v2[101]; int d[101]; int start[101],last[101]; int stn,enn; typedef struct Heap{ bool operator <(Heap T)const{ return T.dis>dis; } int dis,x; }; priority_queue<Heap>Q; void add(int a,int b,int c){ e[++tot].x=b; e[tot].w=c; e[tot].next=k[a]; k[a]=tot; } int i; /* void Dijkstra(int s){ while (!Q.empty()) Q.pop(); memset(v,0,sizeof(v)); memset(d,0,sizeof(d)); Heap tt; tt.dis=0; tt.x=s; Q.push(tt); while (!Q.empty()){ Heap x=Q.top(); Q.pop(); if (v[x.x]) continue; v[x.x]=true; for (int t=k[x.x];t;t=e[t].next){ if (d[e[t].x]<d[x.x]+e[t].w){ d[e[t].x]=d[x.x]+e[t].w; Heap p; p.x=e[t].x; p.dis=d[e[t].x]; Q.push(p); } } } for (int i=1;i<=enn;i++){ if (d[last[i]]>ans) ans=d[last[i]]; } } */ void DFS(int x,int d,int s){ if (d>ans) ans=d; if (s!=0) v[x]=true; for (int t=k[x];t;t=e[t].next){ if (d+e[t].w>ans) ans=d+e[t].w; if (!v[e[t].x]){ v2[e[t].x]=true; DFS(e[t].x,d+e[t].w,s+1); v2[e[t].x]=false; } } v[x]=false; } int main(){ freopen("hex.in","r",stdin); freopen("hex.out","w",stdout); scanf("%d\n",&n); for (int i=1;i<=n;i++){ scanf("%s\n",s); int len=strlen(s); int st,en; if (len>=2) en=(s[len-2]-'0')*10+s[len-1]-'0'; else en=s[len-1]-'0'; if (len & 1) st=(s[0]-'0'); else st=(s[0]-'0')*10+s[1]-'0'; add(st,en,len); if (!vst[st]){ vst[st]=true; start[++stn]=st; } if (!ven[en]){ ven[en]=true; last[++enn]=en; } } for (i=1;i<=stn;i++){ // v[start[i]]=true; DFS(start[i],0,0); // v[start[i]]=false; } printf("%d\n",ans); return 0; }