2018-2019赛季多校联合新生训练赛第五场(2018/12/14)补题题解

A 【字符串】ISBN号码(字符串基础)

字符串基础题,注意一下x的特判即可

代码

#include <bits/stdc++.h>
using namespace std;
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  string a;
  int p=1,sum=0;
  cin>>a;
  for(int i=0;i<a.size()-1;i++)
  if(isdigit(a[i]))
  sum+=(a[i]-'0')*p++;
  sum%=11;
  if(sum==10)
  {
    if(a[a.size()-1]=='X')
    cout<<"Right";
    else
    {
      for(int i=0;i<a.size()-1;i++)
      cout<<a[i];
      cout<<'X';
    }
  }
  else
  {
    if(char(sum+'0')==a[a.size()-1])
    cout<<"Right";
    else
    {
      for(int i=0;i<a.size()-1;i++)
      cout<<a[i];
      cout<<char(sum+'0');
    }
  }
 
}

B 第N个智慧数(数学)

打表题

解法

把所有的平方差都枚举一下

for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
cout<<i*i-j*j;

这样还会出现重复的项,并且还是乱序的,我是打出表来之后再把他们放到set中进行进行去重与排序然后输出即可

代码

#include <bits/stdc++.h>
using namespace std;
int bk[]={这里是打表};
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    set<int> st;
    for(int i=0;i<4950;i++)
    st.insert(bk[i]);
    int n,sum=0;
    cin>>n;
    for(auto it=st.begin();it!=st.end();it++)
    {
        sum++;
        if(sum==n)
        {
            cout<<*it;
            break;
        }
    }
}

C 第m大的身份证号码(字符串基础)

这个把他们用个sort排序一下就可以了

代码

#include <bits/stdc++.h>
using namespace std;
string num[1666],num1[666];
bool cmp(string a,string b)
{
  string t1="",t2="";
  for(int i=6;i<=13;i++)
  t1+=a[i];
  for(int i=6;i<=13;i++)
  t2+=b[i];
  return t1<t2;
}
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n,k;
  cin>>n>>k;
  for(int i=0;i<n;i++)
  cin>>num[i];
  sort(num,num+n,cmp);
  cout<<num[k-1];
}

D 锯木棍(模拟)

这个题直接模拟即可

解法

因为涂色,所以我们可以把这个木块当一个桶,涂色等于桶上的点放入了东西。因为涂两种颜色且两种颜色都是长度的约数,因此我们可以直接进行扫描

第一遍扫描扫最大值

第二遍扫描扫等于最大值的数量

代码

#include <bits/stdc++.h>
using namespace std;
int bk[100015];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int l,m,n,maxn=-1,sum=0,ans=0;
    cin>>l>>m>>n;
    int s1=l/m;
    int s2=l/n;
    for(int i=1;i<=l;i++)
    if(i%s1==0)
    bk[i]=1;
    for(int i=1;i<=l;i++)
    if(i%s2==0)
    bk[i]=1;
    for(int i=1;i<=l;i++)
    {
      if(bk[i]==0)
      sum++;
      else
      {
        sum++;
        maxn=max(maxn,sum);
        sum=0;
      }
    }
    for(int i=1;i<=l;i++)
    {
      if(bk[i]==0)
      sum++;
      else
      {
        sum++;
        if(sum==maxn)
        ans++;
        sum=0;
      }
    }
    cout<<maxn<<" "<<ans;
}

E 坐标统计(基础编程能力)

直接放入然后扫描比较即可

代码

#include <bits/stdc++.h>
using namespace std;
struct node
{
  int x,y;
}zb[10000];
int sum[10000];
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n,maxn=-1,id;
  cin>>n;
  for(int i=0;i<n;i++)
  cin>>zb[i].x>>zb[i].y;
  for(int i=0;i<n;i++)
  for(int j=0;j<n;j++)
  if(zb[j].x<zb[i].x&&zb[j].y<zb[i].y)
  sum[i]++;
  for(int i=0;i<n;i++)
  {
    if(sum[i]>=maxn)
    {
      maxn=sum[i];
      id=i+1;
    }
    cout<<sum[i]<<"\n";
  }
  cout<<id;
}

F 打印月历(基础编程能力)

可能这个题分到基础编程能力有点感觉不大合适,但是这个题确实没有别的什么难的知识点只是需要注意一些地方

解法

①首先就是这个闰年的问题,闰年的2月还平年的2月是不一样的

②然后是计算这月距离第一个月的第一天有几天

③然后推出这个月的第一天是在星期几

int t=(sum)%7;
  int day=(n+t-1)%7+1;

其中day变量就是星期几

④之后再算出这个月具体多少天,这个还得分闰年和平年

⑤然后按照1到这个月的天数输出即可(这里之前还要把那些空格打印出来)

⑥注意第一行一定没有空行要不格式错误(测试数据 2015 2 4)

⑦还有数字用%-4d

代码

#include <bits/stdc++.h>
using namespace std;
int month[]={0,31,0,31,30,31,30,31,31,30,31,30,31};
int main()
{
  /*ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);*/
  int y,m,n,yn;
  cin>>y>>m>>n;
  cout<<"S   M   T   W   T   F   S\n";
  if(y%4==0&&y%100!=0||y%400==0)
  yn=1;
  else
  yn=0;
  int c=m-1,mth,sum=0;
  for(int i=1;i<c+1;i++)
  {
    if(i==2)
    {
      if(yn)
      sum+=29;
      else
      sum+=28;
    }
    sum+=month[i];
  }
  int t=(sum)%7;
  int day=(n+t-1)%7+1;
  for(int i=0;i<(day%7)*4;i++)
  cout<<" ";
  if(m==2)
  {
    if(yn)
    mth=29;
    else
    mth=28;
  }
  else
  mth=month[m];
  int ft=1;
  for(int i=1;i<=mth;i++)
  {
    if(day==7)
    {
      if(!ft)
      cout<<"\n";
      day=0;
    }
    printf("%-4d",i);
    day++;
    ft=0;
  }
}

G 分割绳子(二分查找)

这个地方比赛的时候,都已经做出来了,就是因为二分查找带小数的东西有些细节不会找,导致的出现了问题

对于小数点的精度问题,我们不能单纯的用l<=r而是用带精度的

这个题我们要精确到小数点后两位,那么我们可以用

while(l<=r-0.001)
//do something

其中mid也是double的,之前l=mid+1也变成了l=mid+0.001 r也相同的道理

这个题原题应该没有什么问题吧,裸二分查找

判断函数也是判断一下当前mid值能分割出几个绳子即可

代码

#include <bits/stdc++.h>
using namespace std;
double num[1005];
int n,k;
int isok(double m)
{
  int sum=0;
  for(int i=0;i<n;i++)
  sum+=num[i]/m;
  return sum>=k;
}
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  double l=0,r;
  cin>>n>>k;
  for(int i=0;i<n;i++)
  cin>>num[i],r=max(r,num[i]);
  while(l<=r-0.001)
  {
    double mid=(l+r)/2;
    if(isok(mid))
    l=mid+0.001;
    else
    r=mid-0.001;
  }
  printf("%.2f",l-0.001);
}

H 换座位(语法基础)

排序一次跟原来比较一下看哪里不一样了

代码

#include <bits/stdc++.h>
using namespace std;
int num[666],num1[666];
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n,sum=0;
  cin>>n;
  for(int i=0;i<n;i++)
  cin>>num[i],num1[i]=num[i];
  sort(num,num+n);
  for(int i=0;i<n;i++)
  if(num[i]!=num1[i])
  sum++;
  cout<<sum;
}

I 找M进制数(字符串基础)

这个题我还因为细节问题罚时两次

需要注意的细节

①十进制以下是否出现了字母或者大于等于当前进制的数

②十进制以上是否出现了大于等于当前进制的字母

③第一位数字是否为0(听说这个数据中好像没有给出)、

代码

#include <bits/stdc++.h>
using namespace std;
struct node
{
  int x,y;
}zb[10000];
int sum[10000];
string st[100005];
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n,maxn=-1,id;
  cin>>n>>id;
  int ans=n;
  for(int i=0;i<n;i++)
  cin>>st[i];
  for(int i=0;i<n;i++)
  for(int j=0;j<st[i].size();j++)
  {
    if(st[i][0]=='0')
    {
      ans--;
      break;
    }
    if(id<=10)
    {
      if(isalpha(st[i][j]))
      {
        ans--;
        break;
      }
      if(isdigit(st[i][j]))
      {
        if(st[i][j]-'0'>id-1)
        {
          ans--;
          break;
        }
      }
    }
    if(id>10)
    {
      if(isalpha(st[i][j]))
      {
        if(st[i][j]>'A'+id-11)
        {
          ans--;
          break;
        }
      }
    }
  }
  cout<<ans;
}

J 循环小数(字符串模拟)

这个题并不难啊,比起紫书上那个90年代的acm世界决赛的真题来说还是太嫩了点

解法

①找出循环节前的小数

②找出循环节

③把循环节循环多次加到循环节前的小数后面(这里一定要比给定的要找的位数要多)

④按照要求输出即可

代码

#include <bits/stdc++.h>
using namespace std;
int bk[100015];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n,f=0,ff=0;
    cin>>n;
    string a,nu="",xh="";
    cin>>a;
    for(int i=0;i<a.size();i++)
    {
      if(a[i]=='.')
      f=1;
      if(a[i]=='(')
      ff=1;
      if(f&&!ff)
      {
          if(isdigit(a[i]))
          nu+=a[i];
      }
      if(f&&ff)
      {
        if(isdigit(a[i]))
        xh+=a[i];
      }
    }
    for(int i=0;i<100005;i++)
    nu+=xh;
    cout<<nu[n-1];
}

K 单纯质因数(数论)

当时一直打表还不知道哪里打错了,实际上这个题可以直接暴力去做

我这里又学到了一种O(N根号(N))的分解质因数的算法

这里可以直接用朴素的思想,如果他没有相同的质因数,那么肯定就是把所有的质因数乘起来就等于原来的说

好,我们用这个思想去做,从2到n每个数枚举一遍看他是不是质因数

然后就超时了,因为O(N*N)对于1e5来说还是太大了(当然你可以打表啊,打出5万以内的素数表)

这里介绍一种O(N*根号(N))的分解因数的方法

for(int j=2;j*j<=i;j++)
{
    if(i%j==0)
    {
        if(isp(j))
        sum*=j;
        if(i/j!=j&&isp(i/j))
        sum*=(i/j);
    }
}

这里第一个条件就是朴素的找到质因数,第二个条件就是如果这个数除以找到的这个数不等于原来的(符合条件一不同的因数)且是质数(符合条件二是质因数)

代码

#include <bits/stdc++.h>
using namespace std;
int isp(int n)
{
  for(int i=2;i*i<=n;i++)
  if(n%i==0)
  return 0;
  return 1;
}
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin>>n;
  for(int i=6;i<=n;i++)
  {
    if(isp(i))
    continue;
    int jk=1;
    for(int j=2;j*j<=i;j++)
    if(i%j==0)
    {
      if(isp(j))
      jk*=j;
      if(i/j!=j&&isp(i/j))
      jk*=(i/j);
      if(jk==i)
      {
        cout<<i<<" ";
        break;
      }
    }
  }
}

L 安装饮水机(贪心)

实际上这个就是经典的区间选点问题的贪心,把给的数据化成一个一个的区间然后贪心即可

代码

#include <bits/stdc++.h>
using namespace std;
struct node
{
  int l,r;
}num[10000];
bool cmp(node a,node b)
{
  return a.r==b.r?a.l>b.l:a.r<b.r;
}
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin>>n;
  for(int i=0;i<n;i++)
  {
    int t1,t2;
    cin>>t1>>t2;
    int l=t1-t2;
    int r=t1+t2;
    if(l<0)
    l=0;
    num[i].l=l;
    num[i].r=r;
  }
  sort(num,num+n,cmp);
  int now=num[0].r,ans=1;
  for(int i=1;i<n;i++)
  if(num[i].l>now)
  {
    ans++;
    now=num[i].r;
  }
  cout<<ans;
}

M 分木块(语法基础)

代码

#include <bits/stdc++.h>
using namespace std;
int num[666],num1[666];
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n,sum=0,r1=0,r2=0,r3=0;
  cin>>n;
  for(int i=0;i<n;i++)
  {
    int t,ans1=0,ans2=0,ans3=0;
    cin>>t;
    ans1+=t/100;
    t%=100;
    ans2+=t/10;
    t%=10;
    ans3+=t;
    r1+=ans1;
    r2+=ans2;
    r3+=ans3;
  }
  cout<<r1<<"\n"<<r2<<"\n"<<r3;
}

N 活动人数(语法基础)

代码

#include <bits/stdc++.h>
using namespace std;
int num[1666],num1[666];
int main()
{
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n,sum=0,r1=0,r2=0,r3=0,l,k;
  cin>>n>>l>>k;
  for(int i=0;i<n;i++)
  cin>>num[i];
  sort(num,num+n);
    for(int i=0;i<n;i++)
    if(1)
    {
      if(l>=num[i])
      {
        sum++;
        l+=k;
      }
    }
    cout<<sum;
}
posted @ 2018-12-15 00:38  baccano!  阅读(381)  评论(0编辑  收藏  举报