| 题目名称 | sum | damage | lis |
| 输入文件 | sum.in | damage.in | lis.in |
| 输出文件 | sum.out | damage.out | lis.out |
| 测试点数目 | 10 | 10 | 10 |
| 测试点分数 | 10 | 10 | 10 |
| 时间限制 | 1s | 1s | 1s |
| 空间限制 | 128M | 128M | 128M |
NOIP2011热身赛
DAY1
注意事项:
1、C++同学允许使用所有库。
2、Pascal允许使用math,但是需要生成exe提交。
3、题不难,请耐心答题。
4、把握好做每道题的时间,不要出现某一道题目没有提交的情况。
5、注意文件名的书写,字母均为小写。
5、11:00准时交题,11:03之后提交的不予收取。
一、整数划分(sum.pas/c/cpp)
【题目描述】
从文件中读入一个正整数n(10≤n≤31000)。要求将n写成若干个正整数之和,并且使这些正整数的乘积最大。 例如,n=13,则当n表示为4+3+3+3(或2+2+3+3+3)时,乘积=108为最大。
【输入格式】(sum.in):
一个整数,n
【输出格式】(sum.out):
第1行输出一个整数,为最大乘积的位数。 第2行输出最大乘积的前100位,如果不足100位,则按实际位数输出最大乘积。 (提示:在给定的范围内,最大乘积的位数不超过5000位)。
【输入样例】
13
【输出样例】
3
108
#include <cstdio>#include <cmath>#include <cstring>#include <iostream>using namespace std;int n;int ans[5000];int a[5000];void Multity_small(int *a,int b,int *d){int c[5000];memset(c,0,sizeof(c));int len=a[0]+10;for (int i=1;i<=len;i++){c[i]=a[i]*b;c[i]+=c[i-1] / 10000;c[i-1] %= 10000;}while (c[len]==0 && len>1) len--;c[0]=len;memcpy(d,c,sizeof(c));}void Multity_big(int *a,int *b,int *d){int c[5000];memset(c,0,sizeof(c));for (int i=1;i<=a[0];i++){for (int j=1;j<=b[0];j++){c[i+j-1] +=a[i]*b[j];c[i+j] += c[i+j-1] / 10000;c[i+j-1] %= 10000;}}c[0]=a[0]+b[0]+1;while (c[c[0]]==0 && c[0]>1) --c[0];memcpy(d,c,sizeof(c));}void power(int *a,int b,int *c){int t[5000];for (int i=0;i<=a[0];i++) c[i]=t[i]=a[i];b--;while (b>0){if (b & 1) Multity_big(c,t,c);b >>= 1;Multity_big(t,t,t);}}void print(int *a){printf("%d",a[a[0]]);int tot=(int(log10(a[a[0]]))+1);int i=0;for (i=a[0]-1;i>0;i--){if (tot+4>100) break;tot+=4;if (a[i]<10) printf("000");else if (a[i]<100) printf("00");else if (a[i]<1000) printf("0");printf("%d",a[i]);}if (i>0 && tot>0){if (100-tot==1) printf("%1.1d",a[i]/1000);else if (100-tot==2) printf("%2.2d",a[i]/100);else if (100-tot==3) printf("%3.3d",a[i]/10);}putchar('\n');}int main(){freopen("sum.in","r",stdin);freopen("sum.out","w",stdout);scanf("%d",&n);int t=n / 3;int d=n % 3;if (d==0){a[0]=1;a[1]=3;power(a,t,ans);int p=(ans[0]-1)*4+int(log10(ans[ans[0]]))+1;printf("%d\n",p);print(ans);}else if (d==2){a[0]=1;a[1]=3;power(a,t,ans);Multity_small(ans,2,ans);int p=(ans[0]-1)*4+int(log10(ans[ans[0]]))+1;printf("%d\n",p);print(ans);}else if (d==1){a[0]=1;a[1]=3;power(a,t-1,ans);Multity_small(ans,4,ans);int p=(ans[0]-1)*4+int(log10(ans[ans[0]]))+1;printf("%d\n",p);print(ans);}return 0;}
二、地震(damage.pas/c/cpp)
【题目描述】
农夫John的农场遭受了一场地震。有一些牛棚遭到了损坏,但幸运地,所有牛棚间的路经都还能使用。 FJ的农场有P(1 <= P <= 30,000)个牛棚,编号1..P, C(1 <= C <= 100,000)条双向路经连接这些牛棚,编号为1..C。 路经i连接牛棚a_i和b_i (1 <= a_i<= P;1 <= b_i <= P),路经可能连接a_i到它自己,两个牛棚之间可能有多条路经。农庄在编号为1的牛棚.,N (1 <= N <= P)头在不同牛棚的牛通过手机短信report_j(2 <= report_j <= P)告诉FJ它们的牛棚(report_j)没有损坏,但是它们无法通过路经和没有损坏的牛棚回到到农场。 当FJ接到所有短信之后,找出最小的不可能回到农庄的牛棚数目。这个数目包括损坏的牛棚。
【输入格式】
* 第1行: 三个空格分开的数: P, C, 和 N * 第2..C+1行: 每行两个空格分开的数: a_i 和 b_i * 第C+2..C+N+1行: 每行一个数: report_j
【输出格式】
* 第1行: 一个数,最少不能回到农庄的牛的数目(包括损坏的牛棚).
【输入样例】
4 3 1
1 2
2 3
3 4
3
【输出样例】
3
【hint】
牛棚2遭到损坏,导致牛棚2, 3, 4里面的牛无法回到农庄.
#include <cstdio>#include <cstring>#include <iostream>using namespace std;int n,c,p;int x[110000],y[110000];int v[110000];int fa[110000];struct Edge{int x,next;}e[200001];int first[110000];int tot;void add(int x,int y){e[++tot].x=y;e[tot].next=first[x];first[x]=tot;}int get(int x){if (fa[x]==x) return x;return fa[x]=get(fa[x]);}void Union(int a,int b){int x=get(a);int y=get(b);if (x!=y) fa[x]=y;}int main(){freopen("damage.in","r",stdin);freopen("damage.out","w",stdout);scanf("%d%d%d",&n,&c,&p);for (int i=0;i<c;i++){scanf("%d%d",&x[i],&y[i]);add(x[i],y[i]);add(y[i],x[i]);}for (int i=0;i<p;i++){int d;scanf("%d",&d);for (int t=first[d];t;t=e[t].next){v[e[t].x]=true;}}for (int i=1;i<=n;i++) fa[i]=i;for (int i=0;i<c;i++){if (!v[x[i]] && !v[y[i]]){Union(x[i],y[i]);}}int ans=0;for (int i=2;i<=n;i++){if (get(1)!=get(i)) ans++;}printf("%d\n",ans);return 0;}
三、最长上升子序列(lis.pas/c/cpp)
【题目描述】
给出一个长度为N的整数序列,求出包含它的第K个元素的最长上升子序列。
【输入格式】
第一行两个整数N,K
第二行N个整数
【输出格式】
一个整数L如题目所说的序列长度。
【输入样例】
8 6
65 158 170 299 300 155 207 389
【输出样例】
4
【数据范围】
0<N<=200000,0<K<=N
#include <cstdio>#include <cstring>#include <iostream>using namespace std;int n,k;int a[210000];int q[210000];int top;int find(int x){if (q[top]<x){top++;return top;}int l=1,r=top;while (l<r){int mid=(l+r) >> 1;if (q[mid]<x) l=mid+1;else r=mid;}return l;}int main(){freopen("lis.in","r",stdin);freopen("lis.out","w",stdout);scanf("%d%d",&n,&k);for (int i=1;i<=n;i++){scanf("%d",&a[i]);}for (int i=1;i<k;i++)if (a[i]<a[k]){if (top==0){q[++top]=a[i];}else{int j=find(a[i]);q[j]=a[i];}}int ans=top;top=0;for (int i=k+1;i<=n;i++)if (a[i]>a[k]){if (top==0){q[++top]=a[i];}else{int j=find(a[i]);q[j]=a[i];}}ans+=top+1;printf("%d\n",ans);return 0;}
NOIP2011热身赛
DAY2
|
题目名称 |
Sequence |
Min |
tree |
|
输入文件 |
sequence.in |
min.in |
tree.in |
|
输出文件 |
sequence.out |
min.out |
tree.out |
|
测试点数目 |
10 |
10 |
10 |
|
测试点分数 |
10 |
10 |
10 |
|
时间限制 |
1s |
1s |
1s |
|
空间限制 |
128M |
128M |
128M |
注意事项:
1、C++同学允许使用所有库。
2、Pascal允许使用math,但是需要生成exe提交。
3、题不难,请耐心答题。
4、把握好做每道题的时间,不要出现某一道题目没有提交的情况。
5、注意文件名的书写,字母均为小写。
最大子段和变式
给定一串数Ai(-5000=<Ai<=5000),在这一串数种找到不相交的两个子段使其,使其和最大。
输入格式
第一行一个整数n(n<=200000),表明字串中数的个数。
接下来n行,每行一个整数Ai,(-5000=<Ai<=5000);
输出格式
一个数,表示这一串数中不相交的两个最大子段的和。
输入样例
10
1
-1
2
2
3
-3
4
-4
5
-5
输出样例
13
#include <cstdio>#include <iostream>#define INF 2000000using namespace std;int a[300000];int f[300000];int n;int main(){freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);scanf("%d",&n);int ans=-INF,mymax=-INF,tmp=0;for (int i=1;i<=n;i++){scanf("%d",&a[i]);f[i]=max(f[i-1]+a[i],a[i]);}for (int i=n;i>1;i--){tmp+=a[i];if (tmp>mymax) mymax=tmp;if (ans<f[i-1]+mymax) ans=f[i-1]+mymax;if (tmp<0) tmp=0;}printf("%d\n",ans);return 0;}
最小波动
最小波动是在一串数种出现的一种现象,给定n个数Ai,第i个数的最小波动k=min{|Aj-Ai|}(1=<j<i).而第一个数的最小波动为A1本身。
下面我们给定一串数,让你求出对于每个Ai的最小波动的和。
输入格式
第一行一个整数n(n<=200000),表明字串中数的个数。
接下来n行,每行一个整数Ai,(-32767=<Ai<=32767);
输出格式
一个数sum表示最小波动的和。
输入样例
6
5
1
2
5
4
6
输出格式
12
typelink=^treap;treap=recordlch,rch:link;lnum,rnum,data,heap:longint;end;vartree:link;n,i,j,x,ma:longint;ans:int64;procedure right(var tree:link);varp:link;beginp:=tree^.lch;tree^.lch:=p^.rch;if (p^.rch<>nil) then tree^.lnum:=p^.rnum else tree^.lnum:=0;p^.rch:=tree;p^.rnum:=tree^.lnum+tree^.rnum+1;tree:=p;end;procedure left(var tree:link);varp:link;beginp:=tree^.rch;tree^.rch:=p^.lch;if (p^.lch<>nil) then tree^.rnum:=p^.lnum else tree^.rnum:=0;p^.lch:=tree;p^.lnum:=tree^.lnum+tree^.rnum+1;tree:=p;end;procedure insert(var tree:link;x:longint);beginif (tree=nil) thenbeginnew(tree);tree^.lch:=nil;tree^.rch:=nil;tree^.lnum:=0;tree^.rnum:=0;tree^.data:=x;tree^.heap:=random(maxlongint);endelseif (tree^.data>x) thenbegininc(tree^.lnum);insert(tree^.lch,x);//if (tree^.lch^.heap<tree^.heap) then right(tree);endelsebegininc(tree^.rnum);insert(tree^.rch,x);//if (tree^.rch^.heap<tree^.heap) then left(tree);end;end;procedure searchmin(tree:link;x:longint);beginif (tree=nil) then exit;if (tree^.data>x) thenbeginsearchmin(tree^.lch,x);endelseif (tree^.data=x) thenbeginj:=x;exit;endelsebeginif (j<tree^.data) then j:=tree^.data;searchmin(tree^.rch,x);end;end;procedure searchmax(tree:link;x:longint);beginif (tree=nil) then exit;if (tree^.data<x) thenbeginsearchmax(tree^.rch,x);endelseif (tree^.data=x) thenbeginj:=x;exit;endelsebeginif (j>tree^.data) then j:=tree^.data;searchmax(tree^.lch,x);end;end;beginassign(input,'min.in');reset(input);assign(output,'min.out');rewrite(output);readln(n);tree:=nil;randomize;readln(x);insert(tree,x);ans:=x;for i:=2 to n dobeginreadln(x);j:=-maxlongint;ma:=maxlongint;searchmin(tree,x);if (j<>-maxlongint)and(x-j<ma) then ma:=x-j;j:=maxlongint;searchmax(tree,x);if (j<>maxlongint)and(j-x<ma) then ma:=j-x;inc(ans,ma);insert(tree,x);end;writeln(ans);close(input);close(output);end.
校门外的树
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
|
输入格式 |
|||
|
输入的第一行有两个整数L(1 <= L <= 2亿)和 M(1 <= M <= 20000),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。 |
|||
|
输出格式 |
|||
|
输出包括一行,这一行只包含一个整数,表示马路上剩余的树的数目 输入样例 500 3 150 300 100 200 470 471 输出样例 298 | |||
#include <cstdio>#include <algorithm>#include <iostream>using namespace std; |
浙公网安备 33010602011771号