第三期学员12.25模拟赛题解

falling_cloud

2022-12-23 15:13:00

Personal

## 本场比赛验题人:李溢宸,感谢他做出的贡献。 ## T1 签到 题目要求的求出的正常出勤人数就是这些同学中有在签到表上留下名字的人的数量,因此开一个 `bool` 数组来进行判断,初始状态下全部为 $0$,如果某一个人来了,那么将那个位置设为 $1$,最后表格里有多少个一就是来了多少人。 代码: ``` #include <bits/stdc++.h> using namespace std; bool a[110]={0}; int main() { int i,j,n,m,k,ans=0; cin>>n>>m; for(i=1;i<=m;i++) cin>>k,a[k]=true; for(i=1;i<=n;i++) if(a[i]) ans++; cout<<ans; return 0; } ``` 此题考查对数组的应用。 ## T2 数列 需要意识到的是,只需要移动其中一个数列就可以模拟出所有情况了(虽然把两个数列一同旋转也可以),然后进行模拟和统计即可。并且一个数列在旋转 $n$ 次之后就会恢复原样,所以每个数列只需要转 $n-1$ 次就行了。 模拟的过程按照题目意思进行,先把最后一个数取出来,再将其他数往后移,最后把最后一个数放到第一位就可以了。 | $3$ | $1$ | $4$ | | :----------: | :----------: | :----------: | 记录下最后一个数 $a_n=4$ | $a_n$ | $3$ | $1$ | | :----------: | :----------: | :----------: | | $4$ | $3$ | $1$ | | :----------: | :----------: | :----------: | 这样就是一次旋转的过程。 ``` #include <bits/stdc++.h> using namespace std; int a[105],b[105]; int main() { int i,j,n,Max=0,tot,t; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; for(i=1;i<=n;i++) cin>>b[i]; for(i=1;i<n;i++) { t=a[n]; for(j=n;j>1;j--) a[j]=a[j-1]; a[1]=t; tot=0; for(j=1;j<=n;j++) tot+=a[j]*b[j]; Max=max(tot,Max); } cout<<Max; return 0; } ``` 此题考查对数组内部变化的操作和理解题意中隐藏的条件。 ## T3 植物斗争 显而意见的模拟题,根据每个植物的效果模拟就可以了。具体的模拟过程就是设置两个数组来表示状态,分别代表血量和种子数量,再用两个数组表示每回合受到的临时状态:防御力与受到伤害,在回合结束时做一个判定,如果防御力大于等于受到伤害的话,血量减一,否则不变。 标程中血量数组表示原先血量乘二,这是因为最小的血量单位是 $0.5$,这样的处理不会出现小数,也就是全局都可以用整数来表示。 ``` #include <bits/stdc++.h> using namespace std; int a[1005]={0},b[1005]={0},c[1005]; //a-生命值 b-种子数 c-指向 int g[1005]={0},f[1005]={0}; //该回合受到攻击/防御 int fi[1005]; //每回合植物 int main() { int i,j,t,n,m,k,ans=0; cin>>n>>m; for(i=1;i<=n;i++) a[i]=2; //由于单位是 0.5 所以为避免浮点数,乘二处理 for(t=1;t<=m;t++) { for(i=1;i<=n;i++) cin>>fi[i]; for(i=1;i<=n;i++) cin>>c[i]; for(i=1;i<=n;i++) f[i]=g[i]=0; for(i=1;i<=n;i++) { if(a[i]>0) { if(fi[i]==1) b[i]++; if(fi[i]==2&&b[i]>=1) f[i]=1,b[i]--,g[c[i]]=max(g[c[i]],1); if(fi[i]==3&&b[i]>=2) f[i]=2,b[i]-=2,g[c[i]]=max(g[c[i]],2); if(fi[i]==4) a[i]--,g[c[i]]=max(g[c[i]],1); if(fi[i]==5) f[i]=4; if(fi[i]==6&&b[i]>=4) f[i]=5,b[i]-=4,a[i]++; } } for(i=1;i<=n;i++) if(g[i]>f[i]) a[i]-=2; } for(i=1;i<=n;i++) { if(a[i]<=0) cout<<"out"<<endl; else if(a[i]%2!=0) cout<<a[i]/2<<".5 "<<b[i]<<endl; else cout<<a[i]/2<<" "<<b[i]<<endl; } return 0; } ``` 本题考查数组的运用和对细节的把控,以及对大阅读量文本的理解能力。 ## T4 四则运算 由于题目最后只要求了求出两个极值,所以我们考虑保留住最小值和最大值,在每次运算中枚举 `+` `-` `*` `/` 这四种运算符号即可。 完整证明如下: 从某一位上符号进行分类讨论: `+` `-`:加上一个数,对于有可能出现的所有情况,最大值仍是最大值,最小值也仍是最小值,减去一个数也是同理。 `*`:乘上一个正数时,极值属性不变(即最大最小值仍然由原来的最大最小值运算而来),乘上一个负数时,极值属性转化且由原来极值得来。 换回人话来说,原来的最大值乘上一个负数,它得到的结果一定是原来的数里面运算结果最小的,反之亦然。 `/`:在任何情况下,极值属性不变,可以自己分最大值最小值的正负性进行讨论,这里不做赘述。 ``` #include <bits/stdc++.h> using namespace std; int a[20]; double t[10]; int main() { int i,j,n; double Min,Max; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); Min=Max=a[1]; for(i=2;i<=n;i++) { if(a[i]==0){if(Min>0)Min=0;if(Max<0)Max=0;continue;} t[1]=Max+a[i];t[2]=Max-a[i]; t[3]=Max*a[i];t[4]=Max/a[i]; t[5]=Min+a[i];t[6]=Min-a[i]; t[7]=Min*a[i];t[8]=Min/a[i]; for(j=1;j<=8;j++) { Max=max(Max,t[j]); Min=min(Min,t[j]); } } printf("%.3lf\n%.3lf",Max,Min); return 0; } ``` **注:本题的范围是可以提升至 $600$ 左右的,只放 $10$ 是为了不卡到没有开 `long long` 的人并且放过去 $\Theta(n4^n)$ 的暴搜做法的(以及不需要高精度)。** 本题考查数学思维。