南理工CCF CSP第一次模拟训练
CSDN的编辑器写代码越来越难看了
考虑以后不用CSDN了 (・`ω´・)
Problem A:FinancialManagement
原题链接
题意:输入12个月的工资,输出12个月工资的平均值
题解:定义一个变量sum用于对12个月的工资求和,最后除以12输出即可。签到题
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
double sum=0.0,tmp;
while(~scanf("%lf",&tmp)){
sum+=tmp;
}
printf("$%.2lf\n",sum/12.0);
}
Problem B:Peak
原题链接
题意:判断一个序列,是否有峰值,且这个峰值不能在第一个或最后一个
题解:我们先找到峰值所在地,那么显然,左边的都必须递增,右边的必须递减。以此检测即可。
读题必须细心啊,这道题卡了我半天,原来是数列不允许有相等元素。
AC代码:
#include<iostream>
#include<cstdio>
#define N 100000
using namespace std;
unsigned int a[N];
int main()
{
int n,m;
bool left,right;//用来标记数列左右两端是否找到极大值
int i,j,k;//计数变量
int x, y;//记录左右极大值的位置
cin>>n;//n个测试用例
while(n--)
{
cin>>m;//m个数
left=false;right=false;//初始化
for(i=0;i<m;i++)
cin>>a[i];//接收数列
for(i=0,j=m-1;i<m-1&&j>0;i++,j--)
{//i、j分别从数列左右两端向中间遍历
if(!left&&a[i]>=a[i+1])
{//如果a[i]是左边的极大值
if(i==0)
{//极大值不能出现在数列首端
printf("No\n");
break;
}
x=i;//把极大值的位置记录给x
left=true;//置为真,说明找到左端极大值
}
if(!right&&a[j]>=a[j-1])
{//如果a[j]是右边的极大值
if(j==m-1)
{//极大值不能出现在数列尾端
printf("No\n");
break;
}
y=j;
right=true;
}
if(left&&right)
{//左右都找到极大值
if(x==y)
{//只有左右极大值是同一个位置,才满足题目
cout<<"Yes"<<endl;
break;
}
else
{
cout<<"No"<<endl;
break;
}
}
}
}
return 0;
}
problem C:The Drunk Jailer
原题链接
题意:监狱有n个牢房,编号1~n(5<=n<=100),起初牢房的门是全部关上的,喝醉了的监狱长决定玩一个游戏。对于牢房i我们定义操作A为:如果牢房i的门是关上的,那么打开;反之如果牢房i的门是打开的,那么关上。对于第一轮环节,监狱长将所有的牢房(i=1,2,3,…n)进行一次A操作;第二轮,他将第(i=2,4,6,8,…)个牢房进行A操作;第三轮,他将第(i=3,6,9,12,…)个牢房进行A操作;······问进行n轮之后有多少个牢门是打开的。
题解:第一种方法是直接模拟n次操作;第二种方法是对于每个牢房i,判断总的开关次数,如果开关次数为奇数,那么这个牢房最后的状态为开着,否则为关着。
#include<iostream>
#include<cstring>
using namespace std;
bool a[101];//牢房门的状态
int main()
{
int t,n;
int i,j;
int count;
cin>>t;//测试用例
while(t--)
{
cin>>n;//牢房数
count=0;
memset(a,false,sizeof(a));//初始牢房的门都是关着的,为false
for(i=1;i<=n;i++)
{//n个牢房要进行n此操作,遍历n个操作
for(j=1;j<=n;j++)
{//第i次操作,都是对序号为i*j的牢房操作
if(i*j<=n)
a[i*j]=!a[i*j];//取反,即开/关门
}
}
for(i=1;i<=n;i++)
{//统计a中有多少个true
if(a[i])count++;
}
cout<<count<<endl;
}
return 0;
}
Problem D:Infusion Altar
原题链接
题意:给出一个只包含小写字母、’.’、’#’的n*n(n为奇数且3<=n<=99)的棋盘,可以把棋盘上的任意字符转变为另一个字符,求棋盘为完美对称所需的最小转变次数(完美对称是指棋盘关于横轴、竖轴、两条斜轴都对称,如下图)
题解:把棋盘分成8块部分加4条轴分别考虑。8块部分的只用模拟第一个部分的每个点判断和其他7个部分相等所需最小转变次数合即可。
#include<bits/stdc++.h>
using namespace std;
char str[105][105];
char ch[30];
int main(){
int T;
for(int i=0;i<26;i++) ch[i]=i+'a';
ch[26]='.';
ch[27]='#';
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s",str[i]);
int ans=0;
for(int i=0;i<n/2;i++){//计算4条轴
int mx1=0,mx2=0;
for(int j=0;j<=27;j++){
//计算主对角线和次对角线上的点
int cnt=0;
if(ch[j]==str[i][i]) cnt++;
if(ch[j]==str[n-i-1][n-i-1]) cnt++;
if(ch[j]==str[n-i-1][i]) cnt++;
if(ch[j]==str[i][n-i-1]) cnt++;
mx1=max(mx1,cnt);
//计算横对称轴和竖对称轴上的点
cnt=0;
if(ch[j]==str[n/2][i]) cnt++;
if(ch[j]==str[n/2][n-i-1]) cnt++;
if(ch[j]==str[i][n/2]) cnt++;
if(ch[j]==str[n-i-1][n/2]) cnt++;
mx2=max(mx2,cnt);
}
//遍历结束后,mx1和mx2存储了重复次数最多的字符的次数
ans+=4-mx1;
ans+=4-mx2;
}
for(int i=1;i<n/2;i++){//计算8个部分
for(int j=0;j<i;j++){
int mx=0;
for(int k=0;k<=27;k++){
//主要是数清楚对称的格子是哪一个
int cnt=0;
if(ch[k]==str[i][j]) cnt++;
if(ch[k]==str[j][i]) cnt++;
if(ch[k]==str[j][n-i-1]) cnt++;
if(ch[k]==str[i][n-j-1]) cnt++;
if(ch[k]==str[n-i-1][j]) cnt++;
if(ch[k]==str[n-j-1][i]) cnt++;
if(ch[k]==str[n-j-1][n-i-1]) cnt++;
if(ch[k]==str[n-i-1][n-j-1]) cnt++;
mx=max(mx,cnt);
}
ans+=8-mx;
}
}
printf("%d\n",ans);
}
return 0;
}
Problem E:Cinema in Akiba
原题链接
题意:有n个人去看电影,第i个人坐在第k个空位置上。接下来有m个询问,求解第j个人坐在哪儿。(直接看英文原题吧)
这题题解说用树状数组,但我不是。这题应该可以用STL中的链表和向量很快的解决。因为题目主要的操作是结点的删除,并且要能直接定位到删除的结点,因此vector是最方便的数据结构。
哈哈,如果不是忘记初始化迭代器,这道题就能A了。脑子是个好东西
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int b[3000];
int a[50000];
int f[50000];
int main()
{
vector<int> s;//用来模拟n个空座位
vector<int>::iterator it;
int n,m;
int i,j,k;
int t;
while(scanf("%d",&n)!=EOF)
{
s.clear();//每次清空s
for(i=0;i<n;i++)//第i个人拿到的号是a[i]
scanf("%d",&a[i]);
scanf("%d",&m);//m个询问
for(i=0;i<m;i++)
{//询问是无序的,用b[i]依次记录询问第几个人
//注意这里的“第几个人”都是相对于买票时而言的
scanf("%d",&b[i]);
}
for(i=0;i<n;i++)
s.push_back(i);//初始化空座位
for(i=0;i<n;i++)
{//遍历n个人,安排!
it=s.begin();
it=it+a[i]-1;//迭代器跳到第a[i]-1号空座位
f[i]=*it+1;//把这个空座位是几号赋给f
s.erase(it);//这个座位从s中删除
}
//上面做完,f[i]中就存储了第i个人坐在哪里
for(i=0;i<m;i++)
{//直接查表输出即可
if(i!=0)printf(" ");
printf("%d",f[b[i]-1]);
}
printf("\n");
}
return 0;
}