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; }
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号