2020.12.5--中国计量大学现代科技学院第四届“中竞杯”程序设计校赛(同步赛)
H 变换
链接:https://ac.nowcoder.com/acm/contest/9680/H
来源:牛客网
从前有一个数字 1,它每天要么 +1,要么 *2
现在它变成了 n,请问它最少用了几天变成 n
输入描述:
题目包含多组测试数据,请处理到文件结束。每组输入一行表示一个 N(1≤N≤109)N(1 \leq N \leq 10^9)N(1≤N≤109),代表最终的钱数。保证测试数据的个数不超过 10510 ^ 5105。
输出描述:
对于每个输入,输出一行一个整数表示答案
示例1
输出
复制1 2
比赛做了很长时间才做出来,但想复杂了,比赛结束后给出的做法超简单,只有几行
比赛时AC的代码:
#include<bits/stdc++.h> using namespace std; int main() { long long n,b[10010]={0}; while(scanf("%lld",&n)!=EOF) { long long ct=0,t,i; if(n==1)b[1]=0, cout<<"0"<<endl; else if(n==2)b[2]=1, cout<<"1"<<endl; else { if(n%2!=0) { ct=1; n-=1; for(i=1; ;i++) { t=pow(2,i); if(t>=n)break; } if(t==n)ct+=i; else { ct+=1; n/=2; while(n>1) { if(n%2==0) { ct+=1; n/=2; } else { n-=1; ct+=1; } } } } else{ for(i=1; ;i++) { t=pow(2,i); if(t>=n)break; } //cout<<t<<" "<<i<<endl; if(t==n)ct+=i; else{ ct+=1; n/=2; while(n>1) { if(n%2!=0) { ct+=1; n-=1; } else { ct+=1; n/=2; } } } } printf("%lld\n",ct); } } }
给出的答案:
#include <bits/stdc++.h> using namespace std; int main() { int k; while(cin>>k) { int ans=0; while(k!=1) { if(k%2) k--; else k/=2; ans++; } cout<<ans<<endl; } }
题解:答案会是形如 AAAA...AAAABBBB...BBBB 这样一段序列。此时我们将中间的 BBB...BBBAAA...AAA 使用魔法翻转,即可得到一段字典序不下降的序列。所以我们需要统计每一段 AA...AA 或者 BB..BB 的长度。最后枚举第一段 AAA...AAA 的起点即可。(注意第一段 AAA..AAA 长度为零的情况)
#include<bits/stdc++.h> using namespace std; int main() { int n; string s,b; vector<int>str; cin>>n; getchar(); cin>>s; b+=s[0]; int a=1; for(int i=0;i<n;i++) { if(i!=0&&s[i]!=s[i-1]) { str.push_back(a); b+=s[i]; a=1; } else a++; } str.push_back(a); int ct=0,k=0; for(int i=0;i<b.size()-1;i++) { if(b[i]=='B'&&b[i+1]=='A'){ int num=str[i]+str[i+1]; if(i-1>=0)num+=str[i-1]; if(i+2<str.size())num+=str[i+2]; ct=max(ct,num); k=1; } } if(k==1)cout<<ct<<endl; else cout<<s.size()<<endl; }