2018蓝桥杯省赛(C~F,H~J)(致命小细节,丑数,坑货double)

C

 

判断每个数的因子中有多少个10,2,5.取2和5因子的数量的较小值即可。

AC代码如下:

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
typedef long long ll;
int n,a;
int ma[105][105];
//int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int main(){
//  int cnt=0,cnt5=0,cnt2=0;
//  for(int i=0;i<100;i++){
//      scanf("%d",&a);
//      while(a){
//          if(a%10==0){
//              cnt++;
//              a/=10;
//              continue;
//          }else if(a%5==0){
//              cnt5++;
//              a/=5;
//              continue;
//          }else if(a%2==0){
//              cnt2++;
//              a/=2;
//              continue;
//          }
//          break;
//      }
//  }
//  printf("%d\n",cnt+min(cnt5,cnt2));
    printf("31");
    return 0; 
}  

 

D.

 

 

 

 这题和丑数的思路是一样的。

由于一个数的因子只由3,5,7构成,故肯定能由3,5,7构成下一个数。

故先将1入列。再将其分别与3,5,7相乘后入列。然后1出列(优先队列,最小堆)

之后不断将最小值与3,5,7相乘并入列,再最小值出列。知道找到59084709587505。

看其是第几个出列的即可。

AC代码如下:

#include<iostream>
#include<vector>
#include<queue>
#include<set>
using namespace std;
typedef long long ll;
const int num[3]={3,5,7};
int main(){
    priority_queue< ll,vector<ll>,greater<ll> > q;
    set<ll> s;
    s.insert(1);
    q.push(1);
    for(ll i=1;;i++){
        ll x=q.top();
        q.pop();
        if(x==59084709587505){
            printf("%lld",i-1);
            break;
        }
        for(int j=0;j<3;j++){
            ll x1=x*num[j];
            if(!s.count(x1)){
                s.insert(x1);
                q.push(x1);
            }
        }
    }
    return 0;
}

E题是代码填空题。就懒得看了。

F

 

本题的思路是计算上面去时的时间差和下面来时的时间差。

由于是往返。故时间一来一往分别加上时差和减去时差。

故两个时间差相加就能抵消时差带来的影响。即真实时间为两个时间差相加除2。

对于时间的计算我们可以把它们都换算成秒来相加减减少错误。

不过对于时间化成秒的计算我一开始用了更麻烦且最后错误的方法(不知道错哪了呜呜)

反正直接在scanf中使用格式输入即可。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;//57600
int a[105];
char s[55],e[55];
//ll find_s(char *s,int len){//这是错的,不知道为啥 
//    ll stime=( (s[0]-'0')*10+(s[1]-'0') )*60*60+( (s[3]-'0')*10+(s[4]-'0') )*60+(s[6]-'0')*10+(s[7]-'0');
//    ll etime=( (s[9]-'0')*10+(s[10]-'0') )*60*60+( (s[12]-'0')*10+(s[13]-'0') )*60+(s[15]-'0')*10+(s[16]-'0');
//    if(s[19]=='+'){
//        etime+=(s[20]-'0')*24*60*60;
//    }
//    printf("s:%lld,e:%lld\n",stime,etime);
//    return etime-stime;
//}
ll gettime(){
    int hf,mf,sf,hs,ms,ss;
    scanf("%d:%d:%d %d:%d:%d",&hf,&mf,&sf,&hs,&ms,&ss);
    char tem;
    int f=0;
    while((tem=getchar())!='\n'){
        if(isdigit(tem))
            f=tem-'0';
    }
    ll ff;
    ll s;
    ff=hs*3600+ms*60+ss+f*24*3600;
    s=hf*3600+mf*60+sf;
    return ff-s;
}
int main() {
    int t;
    scanf("%d",&t);
    getchar();
    while(t--){
//          memset(s,0,sizeof(s));//这是错的,不知道为啥 
//        memset(e,0,sizeof(e));
//        gets(s);
//        gets(e);
//        ll se1=find_s(s,strlen(s));
//        ll se2=find_s(e,strlen(e));
//        ll chase=(se2+se1)/2;
        ll se1=gettime();
        ll se2=gettime();
        ll chase=(se2+se1)/2;
        ll h=chase/3600;
        chase%=3600;
        int min=chase/60;
        chase%=60;
        printf("%02lld:%02d:%02d\n",h,min,chase);
    }
    return 0;
}

G题是三维差分。感觉有点难,先cy。

H(BFS)

 

 

 

反正本题时间充裕数据小。我们直接两次bfs。

第一次先找有几座岛(跟北理冬训的一道题几乎一模一样),第二次找每座岛有没有#是上下左右都是#的,若有则岛还活着,若无则岛全没了。

当然可以1次bfs两个操作都弄了。但感觉有点麻烦且怕错。分析复杂度发现随便操作。

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef pair<int,int> pii;
char m[1005][1005];
bool vis[1005][1005];
int to[4][2]={0,1, 1,0, 0,-1, -1,0};
vector<pii >sta;
int n,cnt,ans;
void bfs1(int x,int y){
    queue<pii >q;
    q.push(make_pair(x,y));
    while(!q.empty()){
        int u=q.front().first,v=q.front().second;
        q.pop();
        for(int i=0;i<4;i++){
            int tempx=u+to[i][0],tempy=v+to[i][1];
            if(!vis[tempx][tempy]){
                vis[tempx][tempy]=1;
                if(m[tempx][tempy]=='#')
                    q.push(make_pair(tempx,tempy));
            }
        }
    }
} 
int judge(int x,int y){
    for(int i=0;i<4;i++){
        int tempx=x+to[i][0],tempy=y+to[i][1];
        if(m[tempx][tempy]=='.')
            return 0;
    }
    return 1;
}
int bfs2(int x,int y){
    queue<pii >q;
    q.push(make_pair(x,y));
    while(!q.empty()){
        int u=q.front().first,v=q.front().second;
        if(judge(u,v))
            return 1;
        q.pop();
        for(int i=0;i<4;i++){
            int tempx=u+to[i][0],tempy=v+to[i][1];
            if(!vis[tempx][tempy]){
                vis[tempx][tempy]=1;
                if(m[tempx][tempy]=='#')
                    q.push(make_pair(tempx,tempy));
            }
        }
    }
    return 0;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%s",m[i]+1);
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(m[i][j]=='.'&&!vis[i][j])
                vis[i][j]=1;
            else if(m[i][j]=='#'&&!vis[i][j]){
                sta.push_back(make_pair(i,j));
                ++cnt;
                bfs1(i,j);
            }
        }
    memset(vis,0,sizeof(vis));
    int temp=cnt;
    int len1=sta.size();
    for(int i=0;i<len1;i++){
        if(!bfs2(sta[i].first,sta[i].second)){
            cnt--;
        }
    }
    printf("%d\n",temp-cnt);
    return 0;
}

I

 

本题的思路和cf的一道题思路差不多。是存每个数对k取模后的值。

然后遍历对k取模的值相加后为k的情况计算最大值。(还有两个致命小细节在代码注释里)

由于最多取3个值,则我们只需考虑每个模k后值的最大的三个原值即可。

AC代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#define MAXN 100005
#define MAXM 1005
using namespace std;
typedef long long ll;
int a[MAXN];
vector<int>m[MAXM];
int main() {
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        int temp=a[i]%k;
        m[temp].push_back(a[i]);
    }
    for(int i=0;i<k;++i)
        sort(m[i].rbegin(),m[i].rend());
    int maxn=-1;
    for(int i=0;i<k;++i)
        for(int j=i;j<k;++j){//注意不能如下注释那么写,因为可以(k-1)+(k-1)+2这样构造出一个k倍的 
//      for(int j=0;j<k-i;++j){
            int temp=(k-i-j+k)%k;
            if(!m[temp].empty()&&!m[i].empty()&&!m[j].empty()){
              if(i!=j&&j!=temp&&i!=temp)//互不相同。注意不能只有两个不等式例如i!=j和j!=temp,因为这不能保证i!=temp 
                  maxn=max(maxn,m[i][0]+m[j][0]+m[temp][0]);
              else if(i==j&&j==temp&&m[i].size()>=3)//全都相同 
                  maxn=max(maxn,m[i][0]+m[i][1]+m[i][2]);
              else if(i==j&&j!=temp&&m[i].size()>=2)//i和j相同,temp不同 
                  maxn=max(maxn,m[i][0]+m[i][1]+m[temp][0]);
              else if(i==temp&&j!=temp&&m[i].size()>=2)//i和temp相同,j不同 
                  maxn=max(maxn,m[i][0]+m[i][1]+m[j][0]);
              else if(temp==j&&j!=i&&m[temp].size()>=2)//temp和j相同,i不同 
                  maxn=max(maxn,m[j][0]+m[j][1]+m[i][0]);
            }
        }
    printf("%d",maxn);
    return 0;
}

 

 

J

 

本题贪心求解即可。

 因为要标准差最小,且每个人可以出实数块钱。。。

那么对于每个人只要均分总钱数即可。

如果一个人的钱不够均分的就把他的钱全部拿出并排除后再均分。

直到每个人都够均分即可。(AAyyds)

本题需要注意double这个老是容易在精度上出错的数据类型,因此能用乘法的地方我们尽量都用乘法来提高精度。

(不然大概50~60的那个数据会直接wa)

AC代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#define MAXN 500005
using namespace std;
typedef long long ll;
int n;
double s,a[MAXN];
int main(){
    scanf("%d%lf",&n,&s);
    for(int i=0;i<n;i++)
        scanf("%lf",&a[i]);
    sort(a,a+n);
    double avg=s/n;//计算平均 
    double temp=avg;
    double ans=0,cnt=n;
    for(int i=0;i<n;i++){
        if(a[i]>=temp){//如果剩下的人能够均分的起这笔钱 
            for(int j=0;j<i;++j)
                ans+=(a[j]-avg)*(a[j]-avg);
              ans+=(temp-avg)*(temp-avg)*cnt;
//            for(int j=i;j<n;++j)//错误,这样计算会在精度上出现一些问题。。。相乘减少误差 
//                ans+=(temp-avg)*(temp-avg);
            break;
        }else{//如果他掏空钱包也不能AA 
            s-=a[i];
            --cnt;
            temp=s/cnt;
        }
    }
    printf("%.4lf\n",sqrt(ans/n));
    return 0;
}

 

posted @ 2021-04-08 21:18  mikku  阅读(114)  评论(0)    收藏  举报