南理工CCF CSP第一次模拟训练

南理工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;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值