涵盖知识点:贪心、dp、模拟、二进制etc.
比赛链接:
Educational Codeforces Round 82 (Rated for Div. 2)
A:Erasing Zeroes
题意:至少删几个0使得一个0-1串内所有的1都连续。
题解:记录第一个1的位置和最后一个1的位置输出中间0的个数即可
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int t; 6 cin>>t; 7 while(t--){ 8 string s; 9 cin>>s; 10 int st=-1,ed=-1; 11 for(int i=0;i<s.length();i++){ 12 if(s[i]=='1'){ 13 ed=i; 14 if(st==-1){ 15 st=i; 16 } 17 } 18 } 19 if(st==-1){ 20 cout<<0<<" "; 21 continue; 22 } 23 int res=0; 24 for(int i=st;i<=ed;i++){ 25 if(s[i]=='0') 26 res++; 27 } 28 cout<<res<<" "; 29 } 30 return 0; 31 }
B:National Project
题意:长度为n的道路,每天可以修的长度为1或选择不修,g天好天气和b天坏天气交替出现,要求至少n/2的路是在好天气下修的,问最少几天修完。
题解:先根据间隔算出遇到n/2天好天气总共需要几天,然后在输出长度和天数的较大值即可(要求路全部修完)。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int main(){ 5 int t; 6 cin>>t; 7 while(t--){ 8 ll n,g,b; 9 ll res=0; 10 cin>>n>>g>>b; 11 ll mid=n/2+n%2; 12 ll gap=mid/g; 13 if(mid%g==0)gap--; 14 res+=gap*g; 15 res+=gap*b; 16 res+=(mid-gap*g); 17 cout<<max(res,n)<<" "; 18 } 19 return 0; 20 }
C:Perfect Keyboard
题意:求a-z一共26个字母排成一行的序列,要求给定的密码串的所有相邻字母在所求序列中也相邻。
题解:暴力模拟,每添加一个新的字符到序列中时用map记录下标,若序列中已经存在需要新添加的字符时判断是否符合条件,添加字符时判断是否卡死等情况分类讨论。
AC代码:(写的有点丑,可能有更好的写法或者解法)
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 map<char,int> mp; 5 6 int main(){ 7 int t; 8 cin>>t; 9 while(t--){ 10 mp.clear(); 11 string s; 12 cin>>s; 13 char res[110]; 14 for(int i=0;i<110;i++){ 15 res[i]='#'; 16 } 17 if(s.length()==1){ 18 cout<<"YES "; 19 for(char i='a';i<='z';i++) 20 cout<<i; 21 cout<<" "; 22 continue; 23 } 24 int l=30,r=31; 25 mp[s[0]]=30; 26 mp[s[1]]=31; 27 int idx=31; 28 res[30]=s[0]; 29 res[31]=s[1]; 30 bool flag=true; 31 for(int i=2;i<s.length();i++){ 32 if(s[i]==s[i-2]){ 33 idx=mp[s[i]]; 34 continue; 35 } 36 if(mp[s[i-1]]+1==mp[s[i]]||mp[s[i-1]]-1==mp[s[i]]){ 37 idx=mp[s[i]]; 38 continue; 39 } 40 if(mp[s[i]]!=0){ 41 flag=false; 42 //cout<<"chongfu "; 43 // cout<<i<<" "; 44 //cout<<mp['d']<<" "<<mp['o']<<endl; 45 break; 46 } 47 if(res[idx+1]=='#'){ 48 res[++idx]=s[i]; 49 mp[s[i]]=idx; 50 r=idx; 51 }else if(res[idx-1]=='#'){ 52 res[--idx]=s[i]; 53 mp[s[i]]=idx; 54 l=idx; 55 }else{ 56 flag=false; 57 //cout<<"kasi "; 58 break; 59 } 60 } 61 //cout<<l<<" "<<r<<" "; 62 //for(int i=l;i<=r;i++){ 63 //cout<<res[i]<<" "; 64 //} 65 if(flag){ 66 cout<<"YES "; 67 for(int i=l;i<=r;i++){ 68 cout<<res[i]; 69 } 70 for(char i='a';i<='z';i++){ 71 if(mp[i]==0) 72 cout<<i; 73 } 74 cout<<" "; 75 }else{ 76 cout<<"NO "; 77 } 78 } 79 return 0; 80 }
D:Fill The Bag
题意:给你m个二的倍数,每次操作可以将一个数拆成两半。问你最少几次操作能使n恰好等于其中某些数字的和。
题解:记录m个数的二进制位总和和n的二进制位,若存在相同位对应位数-1,否则将该位向上移动,每两个贡献合并为高一位的一个贡献。若为负数则向高位借用,记录借用的操作数量即为最终答案。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+10; 5 ll cnt[70]; 6 int main(){ 7 int t; 8 cin>>t; 9 while(t--){ 10 memset(cnt,0,sizeof cnt); 11 ll sum=0,n,m; 12 cin>>n>>m; 13 for(int i=1;i<=m;i++){ 14 int x; 15 cin>>x; 16 sum+=x; 17 int p=0; 18 while((x>>p)>1)p++; 19 cnt[p]++; 20 } 21 if(sum<n){ 22 cout<<"-1 "; 23 continue; 24 } 25 int idx=0,ans=0; 26 while(n||cnt[idx]<0){ 27 cnt[idx]-=(n&1); 28 if(cnt[idx]<0){ 29 cnt[idx+1]--; 30 ans++; 31 }else{ 32 cnt[idx+1]+=(cnt[idx]>>1); 33 } 34 n>>=1; 35 idx++; 36 } 37 cout<<ans<<" "; 38 } 39 return 0; 40 }
E:Erase Subsequences
题意:给字符串s,t。问是否存在s的两个子序列可以构成t(两个子序列不存在公共元素)。
题解:遍历每一种构成t的可能(即拆解t为t1,t2)。dp[i][j]=k的状态描述为s的前i个和t1的前j个字符匹配时t2匹配的最大值。若存在一组最后dp值大于等于t2的长度,就符合条件。
思路来源:https://www.bilibili.com/video/av88620060?p=5
AC代码:(注:通过这题发现了string.length()以及string.size()的返回值为size_type类型,是unsigned类型的,如果前面是负数的话直接拿来比较会出锅)
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=410; 4 int dp[maxn][maxn]; 5 bool check(string s,string t){ 6 int idx=0; 7 if(idx==s.length())return true; 8 for(int i=0;i<s.length();i++){ 9 if(s[i]==t[idx])idx++; 10 if(idx==t.length())return true; 11 } 12 return false; 13 } 14 bool check(string s,string t1,string t2){ 15 memset(dp,-1,sizeof dp); 16 dp[0][0]=0; 17 for(int i=0;i<s.length();i++){ 18 for(int j=0;j<=t1.length();j++){ 19 if(dp[i][j]>=0){ 20 if(j<t1.length()&&t1[j]==s[i]) 21 dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]); 22 if(dp[i][j]<t2.length()&&t2[dp[i][j]]==s[i]) 23 dp[i+1][j]=max(dp[i+1][j],dp[i][j]+1); 24 dp[i+1][j]=max(dp[i+1][j],dp[i][j]); 25 } 26 } 27 } 28 int res1= dp[s.length()][t1.length()] ; 29 int res2=t2.length(); 30 //cout<<res1<<" "<<res2<<endl; 31 //cout<<dp[s.length()][t1.length()]<<" "<<t2.length()<<endl; 32 return res1>=res2; 33 // return dp[s.length()][t1.length()]>=t2.length(); 34 } 35 void solve(){ 36 string s,t; 37 cin>>s>>t; 38 if(check(s,t)){ 39 cout<<"YES "; 40 return; 41 } 42 for(int i=0;i<t.length()-1;i++){ 43 string t1="",t2=""; 44 for(int j=0;j<=i;j++) 45 t1+=t[j]; 46 for(int j=i+1;j<t.length();j++) 47 t2+=t[j]; 48 bool res=check(s,t1,t2); 49 if(res){ 50 cout<<"YES "; 51 return; 52 } 53 } 54 cout<<"NO "; 55 } 56 int main(){ 57 int t; 58 cin>>t; 59 while (t--){ 60 solve(); 61 } 62 return 0; 63 }