18/10/26 周五集训队第二次比赛补题题解

这次比赛oj有一些问题,在于linux换行符之类的问题,让我一直卡在了G题,洛谷一直提交都是对的,就学校的不对.....最后发现实际上我的并没有错

A.海港

感觉是相当费劲的一个题,我上来因为比赛的时候样例给的不足让我以为是>86400导致出现了错误。后来看了洛谷的题解,自己写了一个队列又死活RE。看了看第一个题解,发现也倒是不用开队列,直接用数组计数就行了。

这个题的思路是开三个数组,一个表示时间,一个表示数量,一个表示记录。

难点在于计算时间的问题,如果没有时间障碍的话,我们直接一个set,这个时间我用之前的方法开了队列,然后把所有元素放进队列,每次要输出答案的时候都进行一次for循环并开一个记录时间下标的数组,如果没有标记的话且当前时间减去循环的时间>=86400的话,是第一个下标然后枚举出第二个下标再按照数组记录的数量进行出队操作即可然后TLE,WA,模拟失败,模拟相当麻烦。

看了洛谷的题解,实际上不一定只用一个数组的元素来记录时间,也就是说可以把每个数给定义一个时间,使时间数组的编号对应人种数组的编号,那么跟原来一样开记录数组如果记录==1人种数+1,然后最后用了一个while(当前时间-从头开始的时间>=86400)就进行把bk对应的i--的工作,如果bk数组等于0的话那么一定可以肯定人种少了,并且之后重复的相减也并不影响,因为i放在了外面,这个写法确实是太强了

代码

#include <bits/stdc++.h>
using namespace std;
int tie[300010];
int st[300010];
int bk[300010];
int main()
{
  int n,i=0,ans=0,r=0;
  cin>>n;
  while(n--)
  {
    int t,num;
    cin>>t>>num;
    while(num--)
    {
      int k;
      tie[++r]=t;
      cin>>st[r];
      if(!bk[st[r]])
      ans++;
      bk[st[r]]++;
    }
    while(t-tie[i]>=86400)
    {
      if(!--bk[st[i++]])
      ans--;
    }
    cout<<ans<<endl;
  }
}

B.魔法阵(待研究)

C.金币

做起来不是很顺得调试了一会,然后直接按照规律递推求得

代码

#include <bits/stdc++.h>
using namespace std;
int sum[10050];
main()
{
    int t=0,zq=1,gz=1,mn=0;
    for(int i=1;i<=10010;i++)
    {
      if(t<zq)
      {
        mn+=gz;
        sum[i]=mn;
        t++;
      }
      else
      {
        mn+=++gz;
        sum[i]=mn;
        zq++;
        t=1;
      }
    }
    int n;
    cin>>n;
    cout<<sum[n];
}

D.回文日期

完全的思维题,可以直接八位数枚举然后超时,实际上可以直接枚举年份就行,然后判断一下月份和日期是不是在两个数的区间之内,就能很快的AC了

代码

#include <bits/stdc++.h>
using namespace std;
int mth[]={0,31,29,31,30,31,30,31,31,30,31,30,31};
int main()
{
  int a,b,sum=0;
  cin>>a>>b;
  int y1=a/10000;
  int y2=b/10000;
  int m1=a/100%100;
  int m2=b/100%100;
  int d1=a%100;
  int d2=b%100;
  for(int i=y1;i<=y2;i++)
  {
    stringstream s;
    s<<i;
    string ss;
    s>>ss;
    s.clear();
    string s1=ss;
    reverse(ss.begin(),ss.end());
    string ans=s1+ss;
    s<<ans;
    int ans1;
    s>>ans1;
    int y3=ans1/10000;
    int m3=ans1/100%100;
    int d3=ans1%100;
    //cout<<y3<<" "<<m3<<" "<<d3<<endl;
    if(m3>=1&&m3<=12&&d3>=1&&d3<=mth[m3])//这里不用判断是不是闰年,因为如果是闰年的话那么就是0229倒过来就是92200229这是一个回文日期,其他的一定不是,所以直接二月锁定29即可
    {
      if(i==y1)
      {
        if(m3>m1||(m3==m1&&d3>=d1))
        {
          sum++;
        }
      }
      else if(y3<y2||m3<m2||m3==m2&&d3<=d2)//这里判断是不是在区间内,用的是||开关性
      {
        sum++;
        //cout<<ans<<endl;
      }
    }
  }
  cout<<sum;

}

E.求和(待研究)

F.推销员(放弃,图论题)

G.扫雷游戏

这就是我比赛打蹦,心态崩了的罪魁祸首,明明写一个函数进行8方向判断即可,就是因为linux换行oj的问题导致不通过。。。导致心态爆炸,后来又换了洛谷的写法才过了的,真是。。。。

本来以为DFS了,结果发现只需要把字符串处理一下,然后把?周围的地雷找一找就行了

代码

#include <bits/stdc++.h>
using namespace std;
string st[110];
int mp[110][110];
int bk[110][100];
void check(int x,int y)
{
  for(int i=-1;i<=1;i++)
  for(int j=-1;j<=1;j++)
  if(i!=0||j!=0)
  {
    if(mp[x+i][y+j]==1)
    bk[x][y]++;
  }
}
main()
{
  int n,m;
  cin>>n>>m;
  getchar();
  for(int i=0;i<n;i++)
  getline(cin,st[i]);
  for(int i=0;i<n;i++)
  for(int j=0;j<m;j++)
  {
    if(st[i][j]=='*')
    mp[i][j]=1;
    else
    mp[i][j]=0;
  }
  for(int i=0;i<n;i++)
  for(int j=0;j<m;j++)
  {
    if(mp[i][j]==0)
    check(i,j);
    else
    bk[i][j]=-1;
  }
  //memset(bk,-1,sizeof(bk));
  for(int i=0;i<n;i++)
  {
    for(int j=0;j<m;j++)
    {
      if(bk[i][j]==-1)
      cout<<"*";
      else
      cout<<bk[i][j];
    }
    cout<<endl;
  }
}

H.买铅笔

不知道是什么题,反正就7个数,直接硬解得了,应该可以贪心吧

代码

#include <bits/stdc++.h>
using namespace std;
main()
{
  int n;
  cin>>n;
  int t1,k1,t2,k2,t3,k3;
  cin>>t1>>k1>>t2>>k2>>t3>>k3;
  int sum1,sum2,sum3;
  sum1=k1,sum2=k2,sum3=k3;
  int t11=t1,t22=t2,t33=t3;
  while(t11<n)
  {
    t11+=t1;
    sum1+=k1;
  }
  while(t22<n)
  {
    t22+=t2;
    sum2+=k2;
  }
  while(t33<n)
  {
    t33+=t3;
    sum3+=k3;
  }
  //cout<<sum1<<" "<<sum2<<" "<<sum3<<endl;
  cout<<min(min(sum1,sum2),min(sum1,sum3));
}
原文地址:https://www.cnblogs.com/baccano-acmer/p/9863491.html