Educational Codeforces Round 82 (Rated for Div. 2)
A. Erasing Zeroes
题意:大概意思就是给一个01字符串,最少次数删除0后使字符串中的所有1组成一个连续的子段。
思路:1.队列存始末1的位置,计算其距离 和1个数之差。
2.标记始末1的位置,统计其中0的个数。
#include<iostream> #include<queue> #include<cstdio> #include<cstring> using namespace std; queue<int> qe; int main(){ int t; char s[105]; cin>>t; while(t--){ cin>>s; int cnt =0,ans =0; while(!qe.empty())qe.pop(); int num = strlen(s+1); for(int i=0;i<=num;i++){ char c =s[i]; if(c == '1'){ qe.push(i); cnt++; } } if(qe.size()==0 ) ans =0; else if(qe.back() - qe.front() +1 >= cnt){ ans = qe.back()-qe.front()+1 -cnt; } cout<<ans<<endl; } return 0; }
#include<iostream> #include<queue> #include<cstdio> #include<cstring> using namespace std; int main(){ int t; string s; cin>>t; while(t--){ cin >> s; int ans = 0, cnt = 0; bool first = true; for (int i = 0; i < s.size(); ++i) { if (s[i] == '1') { first = false; ans += cnt; cnt = 0; } if (s[i] == '0' && !first) cnt++; } cout << ans << endl; } return 0; }
B. National Project
题意:修一条长度为n的路,要求至少一半是good的。注意在每[1,g]天可以修good的路,然后每[g+1,g+b]天可以修bad的路,依次交替。问按要求修完整条路需要的最短时间。
思路:计算出至少一半好路在g情况下需要的天数,乘上周期,再减去b。
#include<bits/stdc++.h> using namespace std; void run(){ long long n,g,b,ans; cin >> n >> g >> b; long long mid = ceil(n*1.0/2); if(mid % g == 0 ) ans = (g+b)*(mid/g) - b; else ans = (g+b)*(mid/g)+mid%g; cout<<max(ans,n)<<endl; } int main(){ int t; cin>> t; while(t--) run(); return 0; }
C. Perfect Keyboard
题意:给出s串,|s| ≤ 100。
现在构造一个由26个小写字母组成的t串,要求对于任意两个在s串中相邻的字符,在tt串中都相邻。
如果不能构造则输出NO。
思路:可以使用贪婪算法解决该问题。 我们将使用字符串中已经遇到的字母以及布局上的当前位置来维护键盘的当前布局。如果字符串的下一个字母已经在布局上,则它必须与当前字母相邻,否则将没有答案。如果还没有这样的字母,我们可以将其添加到相邻的自由位置,如果两个字母都被占用,则没有答案。最后,您必须添加不在字符串s中的字母。
#include<bits/stdc++.h> using namespace std; void run(){ string s; cin>> s; int vis[26]; memset(vis,0,sizeof vis); vis[s[0] -'a'] =1; string t(1,s[0]); int pos=0; for(int i=1;i<s.size();i++){ if(vis[s[i]-'a']){ if(pos >0 && s[i] == t[pos -1]){ pos--; } else if( pos +1 < t.size() && s[i] == t[pos +1]){ pos++; } else { cout<<"NO"<<endl; return; } }else{ if(pos == 0 ) t = s[i] +t; else if( pos == t.size() -1) { t+=s[i]; pos++; }else{ cout<<"NO"<<endl; return ; } } vis[s[i]-'a']=1; } for(int i=0;i<26;i++){ if(!vis[i]) t+=char('a'+i); } cout<<"YES"<<endl<<t<<endl; } int main(){ int t; cin>>t ; while(t--)run(); return 0; }
D. Fill The Bag
题意:现有一背包,容量为n,n ≤ 1018,有m个物品,每个物品占用容量为ai,1 ≤ ai ≤ 109,保证对于每个ai都存在一个非负整数x,使得2x=ai。
现在可以执行任意次如下操作:将ai划分为两个ai/2。
现在要用最少的划分次数,来填满这个背包
思路:显然可以发现,如果对n进行二进制分解,那么我们只需要保证对应二进制位上面为1即可。
所以贪心策略为:对于某一位而言,肯定能用前面的来堆就用前面的,否则就把后面最近的一个分解,使得这一位为11。
实现时我们从低位到高位考虑,某一位考虑完过后,这一位剩下的显然堆在后面最优。如果从高位往低位考虑,则贪心起来十分困难。
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; int a[N]; int bit[64]; void run(){ for(int i=0;i<64;i++) bit[i]=0; long long n,ans=0,sum = 0;int m; cin>> n >>m; for(int i=1;i<=m;i++){ cin>>a[i];sum+=a[i]; int x = a[i]/2,t=0; while(x){ t++; x /=2; } ++bit[t]; } if(sum < n ) { cout<<-1<<endl; return ; } for(int i = 0; i<64;i++){ bool need = false; if( n >>i & 1 ) need = true; if( bit[i] ==0 && need){ for(int j=i+1; j<64;j++){ if(bit[j]>=1){ ans += j -i; for(int k =i ;k<j;k++) ++bit[k]; ++bit[i],--bit[j]; break; } } } if(need) --bit[i]; bit[i + 1 ] += bit[i] /2; } cout<<ans<<endl; } int main(){ int t;cin>>t; while(t--)run(); return 0; }

浙公网安备 33010602011771号