20180303开学测总结

上上周进行了开学测,现在补上一篇题解

难度不算太大,但只有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("\n%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("\n");
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\n",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\n",ans[i]); 
58     return 0; 
59 } 

 

 

得分:30

 

总分:

100+80+100+30=310

 

总结:

总体都很水,可以算得上是NOIP普及组比较简单的那种总难度。

但是我感觉有失误,首先T2不应该错,假如给多1h,我可能可以A过T4,但时间就还是有点短啊。

posted @ 2018-03-16 21:05  MN2016  阅读(952)  评论(0编辑  收藏  举报