上上周进行了开学测,现在补上一篇题解
难度不算太大,但只有2h,所以时间比较紧,本来老师要求初二的只做T3T4,但我也还是都打完了。
1、成绩(score)
【题目描述】
分析:
这道题一看感觉好熟悉,没错就是NOIP2017 普及的T1,所以5分钟的问题,随随便便A掉。
代码:
1 #include<cstdio> 2 using namespace std; 3 int a,b,c; 4 int main() 5 { 6 freopen("score.in","r",stdin); 7 freopen("score.out","w",stdout); 8 scanf("%d%d%d",&a,&b,&c); 9 printf("%d",a/5+b/10*3+c/2); 10 fclose(stdin); 11 fclose(stdout); 12 return 0; 13 }
得分:100
2、程序员输入问题(editor)
【题目描述】
程序员输入程序,出现差错时可以采取以下的补救措施:敲错了一个键时,可以补敲一个退格符“#”,以表示前一个字符无效;发现当前一行有错,可以敲入一个退行符“@”,以表示“@”与前一个换行符之间的字符全部无效。如:在终端上输入了这样两行字符:
PRKJ##OGRAN#M LX;
VAR@CONST N:#=10;
则实际有效的是:
PROGRAM LX;
CONST N=10;
【输入格式】
editor.in 输入一行字符,个数不超过100
【输出格式】
editor.out 输出一行字符,表示实际有效字符
【输入样例】
sdfosif@for(ii#=1,#;i<.#=8;i+++#);
【输出样例】
for(i=1;i<=8;i++);
分析:
这是一道字符串的处理题,因为是最后十分钟才做的,所以没有检查,没有推敲,其实用栈来解决非常方便,当时可能打漏了一点条件吧,所以wa了两个点。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 6 int len,last,top; 7 char a[150],b[150]; 8 9 int main() 10 { 11 int i,j; 12 gets(a); 13 len=strlen(a); 14 for (i=0;i<len;i++) 15 if (a[i]=='@') 16 last=i; 17 for (i=last+1;i<len;i++) 18 { 19 if (a[i]!='#') 20 b[++top]=a[i]; 21 else 22 --top; 23 } 24 for (i=1;i<=top;i++) 25 putchar(b[i]); 26 return 0; 27 }
得分:80
3、滑动的窗户(window)
【题目描述】
在一个包含n个元素的数组上,有一个长度为k的窗户在从左向右滑动。窗户每滑动到一个位置,我们都可以看到k个元素在窗户中。如下的例子所示,假设数组为 [1 3 -1 -3 5 3 6 7],而k等于3:
对于窗户滑动过的每个位置,请给出窗户内k个元素的最小值和最大值。
【输入格式】 window.in
输入的第一行包括两个整数n,k,n表示数组的长度,k表示窗户的长度。
接下来一行包括n个整数,表示这个n个元素的数组。
【输出格式】window.out
输出包含两行,每行包括n-k+1个整数,第一行表示窗户从左到右滑动过程中的最小值,第二行表示窗户从左到右滑动过程中的最大值。
【输入样例】
8 3
1 3 -1 -3 5 3 6 7
【输出样例】
-1 -3 -3 -3 3 3
3 3 5 5 6 7
【数据范围】
对于100%的数据,3<=n<=1000000,1<=k<=n,数组中每个元素均在int范围内。
分析:
这道题但是一看感觉是一道单调队列的题,很模板,但是我也好像没有正式地打过一遍单调队列(好像唯一一次是在寒假打的),所以我有点怂,先打了一个RMQ的st表,以防万一,也用作对拍,然后花了一个多小时手推单调队列,写了个山寨版的单调,但还是a过去了。
代码:
RMQ对拍:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cctype> 5 using namespace std; 6 7 const int size=1000010; 8 int n,k,a[size],log[60],f[size][40],g[size][40]; 9 10 inline int read() 11 { 12 int x=0,flag=1; 13 char c=getchar(); 14 while (!isdigit(c)) 15 flag=c=='-'?-1:1,c=getchar(); 16 while (isdigit(c)) 17 x=(x<<1)+(x<<3)+(c^48),c=getchar(); 18 return x*flag; 19 } 20 21 inline void dolog() 22 { 23 int i; 24 log[0]=-1; 25 for (i=1;i<=40;i++) 26 log[i]=log[i>>1]+1; 27 } 28 29 inline void init() 30 { 31 int i,j; 32 for (i=1;i<=n;i++) 33 f[i][0]=a[i],g[i][0]=a[i]; 34 for (j=1;j<=log[n];j++) 35 for (i=1;i<=n;i++) 36 { 37 f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]); 38 g[i][j]=min(g[i][j-1],g[i+(1<<j-1)][j-1]); 39 } 40 } 41 42 inline int getmax(int l,int r) 43 { 44 int k=log[r-l+1]; 45 return max(f[l][k],f[r-(1<<k)+1][k]); 46 } 47 48 inline int getmin(int l,int r) 49 { 50 int k=log[r-l+1]; 51 return min(g[l][k],g[r-(1<<k)+1][k]); 52 } 53 54 int main() 55 { 56 // freopen("window.in","r",stdin); 57 // freopen("window.out","w",stdout); 58 int i,j; 59 n=read(); 60 k=read(); 61 for (i=1;i<=n;i++) 62 a[i]=read(); 63 dolog(); 64 init(); 65 printf("%d",getmin(1,k)); 66 for (i=2;i<=n-k+1;i++) 67 printf(" %d",getmin(i,i+k-1)); 68 printf(" %d",getmax(1,k)); 69 for (i=2;i<=n-k+1;i++) 70 printf(" %d",getmax(i,i+k-1)); 71 fclose(stdin); 72 fclose(stdout); 73 return 0; 74 }
山寨单调队列:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cctype> 5 using namespace std; 6 7 const int size=1000010; 8 int n,k,a[size],f[size*3],g[size*3],l,r,flag;//f:min,g:max 9 10 inline int read() 11 { 12 int x=0,flag=1; 13 char c=getchar(); 14 while (!isdigit(c)) 15 flag=c=='-'?-1:1,c=getchar(); 16 while (isdigit(c)) 17 x=(x<<1)+(x<<3)+(c^48),c=getchar(); 18 return x*flag; 19 } 20 21 int main() 22 { 23 freopen("window.in","r",stdin); 24 freopen("window.out","w",stdout); 25 int i,j; 26 n=read(); 27 k=read(); 28 for (i=1;i<=n;i++) 29 a[i]=read(); 30 l=1,r=0; 31 f[++r]=1; 32 flag=0; 33 for (i=1;i<=n;i++) 34 { 35 while (f[l]<i-k+1) 36 l++; 37 while (l<r&&a[f[l]]>=a[f[r]]) 38 l++; 39 if (i>=k) 40 { 41 if (flag==0) 42 printf("%d",a[f[l]]),flag=1; 43 else 44 printf(" %d",a[f[l]]); 45 } 46 while (r>l&&a[i+1]<=a[f[r]]) 47 r--; 48 f[++r]=i+1; 49 } 50 printf(" "); 51 flag=0; 52 l=1,r=0; 53 g[++r]=1; 54 for (i=1;i<=n;i++) 55 { 56 while (g[l]<i-k+1) 57 l++; 58 while (l<r&&a[g[l]]<=a[g[r]]) 59 l++; 60 if (i>=k) 61 { 62 if (flag==0) 63 printf("%d",a[g[l]]),flag=1; 64 else 65 printf(" %d",a[g[l]]); 66 } 67 while (r>l&&a[i+1]>=a[g[r]]) 68 r--; 69 g[++r]=i+1; 70 } 71 fclose(stdin); 72 fclose(stdout); 73 return 0; 74 }
得分:100
4、蒸发学水(water)
【题目描述】
众所周知,TerryHu 是一位大佬,他平时最喜欢做的事就是蒸发学水。 机房的位置一共有n 行m 列,一开始每个位置都有一滴学水,TerryHu 决定在每一个时刻选择一滴学水进行蒸发,直到机房里不再存在学水。 TerryHu 想知道在每个时刻之后,机房里剩下的学水构成了几个联通块。
【输入格式】water.in
第一行包含2 个正整数n,m。 之后n 行每行包含m 个正整数Aij,表示第i 行第j 列的学水在时刻Aij 被蒸发,保证{A}构成了一个n *m 的排列。
【输出格式】water.out
共n * m 行每行包含1 个整数ansi,时刻i 之后剩下的学水构成的联通块的数量。
【输入样例】
2 2
1 3
4 2
【输出样例】
1
2
1
0
【数据范围】
对于60% 的数据:n,m<= 50; 对于100% 的数据:n,m<= 1000。
分析:
这道题的正解应该是并查集,通过从后往前推的一个过程,判断当前节点的上下左右分别构不构成联通块,从而解决。考试时没时间了,所以打了个暴力,但是不知道为什么拿不完60分。
代码:
1 #include<cstdio> 2 #include<cctype> 3 #include<iostream> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 8 const int size=1010; 9 int n,m,ans,tot; 10 int x[5]={0,0,1,0,-1},y[5]={0,-1,0,1,0}; 11 bool map[size][size],run[size][size]; 12 struct node 13 { 14 int val,x,y; 15 }a[size*size]; 16 17 inline int read() 18 { 19 int x=0,flag=1; 20 char c=getchar(); 21 while (!isdigit(c)) 22 flag=c=='-'?-1:1,c=getchar(); 23 while (isdigit(c)) 24 x=(x<<1)+(x<<3)+(c^48),c=getchar(); 25 return x*flag; 26 } 27 28 bool comp(node a,node b) 29 { 30 return a.val<b.val; 31 } 32 33 void dfs(int xx,int yy) 34 { 35 int i; 36 for (i=1;i<=4;i++) 37 if (map[xx+x[i]][yy+y[i]]==0&&run[xx+x[i]][yy+y[i]]==0&&xx+x[i]>=1&&xx+x[i]<=m&&yy+y[i]>=1&&yy+y[i]<=n) 38 { 39 run[xx+x[i]][yy+y[i]]=1; 40 dfs(xx+x[i],yy+y[i]); 41 } 42 } 43 44 int main() 45 { 46 freopen("water.in","r",stdin); 47 freopen("water.out","w",stdout); 48 int i,j,k; 49 n=read(),m=read(); 50 for (i=1;i<=n;i++) 51 for (j=1;j<=m;j++) 52 { 53 a[++tot].val=read(); 54 a[tot].x=i; 55 a[tot].y=j; 56 } 57 sort(a+1,a+tot+1,comp); 58 for (i=1;i<=tot;i++) 59 { 60 ans=0; 61 memset(run,0,sizeof(run)); 62 map[a[i].x][a[i].y]=1; 63 for (k=1;k<=n;k++) 64 for (j=1;j<=m;j++) 65 if (map[k][j]==0&&run[k][j]==0) 66 ans++,dfs(k,j); 67 printf("%d ",ans); 68 } 69 fclose(stdin); 70 fclose(stdout); 71 return 0; 72 }
正解:
1 #include<cstdio> 2 #include<cctype> 3 using namespace std; 4 5 int father[1000010],n,m,a[1010][1010],ans[1000010],x[1000010],y[1000010]; 6 7 int find(int x) 8 { 9 if (father[x]!=x) 10 father[x]=find(father[x]); 11 return father[x]; 12 } 13 14 int read() 15 { 16 int x=0,f=1; 17 char c=getchar(); 18 while (!isdigit(c)) 19 f=c=='-'?-1:1,c=getchar(); 20 while (isdigit(c)) 21 x=(x<<1)+(x<<3)+(c^48),c=getchar(); 22 return x*f; 23 } 24 25 int main() 26 { 27 int i,j; 28 // n=read(); 29 // m=read(); 30 scanf("%d%d",&n,&m); 31 for (i=1;i<=n;i++) 32 for (j=1;j<=m;j++) 33 { 34 scanf("%d",&a[i][j]); 35 x[a[i][j]]=i; 36 y[a[i][j]]=j; 37 father[a[i][j]]=a[i][j]; 38 } 39 for (i=n*m;i>=1;i--) 40 { 41 ans[i]=ans[i+1]+1; 42 int t,p; 43 t=find(i),p=find(a[x[i]-1][y[i]]); 44 if (t&&p&&t!=p&&a[x[i]-1][y[i]]>i) 45 father[t]=p,ans[i]--; 46 t=find(i),p=find(a[x[i]+1][y[i]]); 47 if (t&&p&&t!=p&&a[x[i]+1][y[i]]>i) 48 father[t]=p,ans[i]--; 49 t=find(i),p=find(a[x[i]][y[i]-1]); 50 if (t&&p&&t!=p&&a[x[i]][y[i]-1]>i) 51 father[t]=p,ans[i]--; 52 t=find(i),p=find(a[x[i]][y[i]+1]); 53 if (t&&p&&t!=p&&a[x[i]][y[i]+1]>i) 54 father[t]=p,ans[i]--; 55 } 56 for (i=2;i<=n*m+1;i++) 57 printf("%d ",ans[i]); 58 return 0; 59 }
得分:30
总分:
100+80+100+30=310
总结:
总体都很水,可以算得上是NOIP普及组比较简单的那种总难度。
但是我感觉有失误,首先T2不应该错,假如给多1h,我可能可以A过T4,但时间就还是有点短啊。