A:
题面:
输入一个01字符串,问你最少需要将多少个0变成1,才能使得字符串所有的1都是连续的
solution:
先统计1的个数,记录第一个1的下标i以及最后一个1的下标j,输出j-i+1-sum(1)
std:
#include <bits/stdc++.h> using namespace std; #define ll long long int main() { int n; cin>>n; while(n--) { string s; cin>>s; int sum = 0,cnt1 = 0,cnt2 = 0,l = s.length(); for(int i=0;i<l;i++) { if(s[i] == '1') sum++; } for(int i=0;i<l;i++){ if(s[i] == '1') { cnt1 = i; break ; } } for(int i=l-1;i>=0;i--){ if(s[i] == '1') { cnt2 = i; break ; } } if(sum == 0){ cout<<"0"<<endl; continue ; } cout<<cnt2 - cnt1 + 1 - sum<<endl; } return 0; }
B:
题面:
输入n,a,b。n代表道路的长度,每天可以铺设1m,a代表连续a天铺设符合标准的道路,b代表连续b天铺设不符合标准的道路的天数,工人可以选择某天不铺设道路,但是天数也要计算在内,要求符合标准的道路>=floor(n/2)。即7m的道路至少需要4m,问工人们最少需要多少天才能铺设完所有的道路?
solution:
自己想多了,写了很多if,其实可以二分,也可以直接求
std:
直接求:
#include <bits/stdc++.h> using namespace std; #define ll long long int main() { int n; cin>>n; while(n--) { ll n , g , b; cin>>n>>g>>b; ll x = (n+1)/2; ll y = x/g; ll z = x%g; if(z == 0) { z = g; y--; } cout<<max(n , y*(g+b) + z)<<endl; } return 0; }
二分:
#include <bits/stdc++.h> using namespace std; #define ll long long ll n,b,g; int solve(ll sum) { ll len = (n+1)/2; ll cnt = sum/(g+b); ll res = sum%(g+b); ll gcnt = g*cnt + min(g , res); return gcnt >= len; } int main() { int t; cin>>t; while(t--) { cin>>n>>g>>b; ll l = 0 , r = 1e18,ans = 1e18; while(l <= r) { ll mid = (l+r)>>1; if(solve(mid)){ ans = min(ans , mid); r = mid - 1; }else{ l = mid + 1; } } cout<<max(n , ans)<<endl; } return 0 }
C:
题面:
有一种键盘,只有一行组成,a-z,键盘只能连续敲击相邻的字母,给出敲击出的字符串,请你构造出键盘,如果不存在这样的键盘,输出-1
solution:
拓扑排序思想,我们首先记录相邻的字母,存到vector,如果size>2,输出-1,否则遍历a-z,如果入度等于1,则dfs这个字母,如果入度等于0也要记得输出,
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 1005; vector<int> g[maxn]; int vis[maxn],cnt[maxn]; string ans ; void init() { for(int i=0;i<maxn;i++){ g[i].clear(); vis[i] = 0; } ans = ""; } void dfs(int x) { vis[x] = 1; ans += ('a' + x); for(int i=0;i<g[x].size();i++){ if(!vis[g[x][i]]){ dfs(g[x][i]); } } return ; } int main() { int t; cin>>t; while(t--) { string s; init(); cin>>s; map< pair<int ,int > , int > mp; for(int i=1;i<s.length();i++) { int a = s[i] - 'a'; int b = s[i-1] - 'a'; if(a > b) swap(a , b); if(mp[make_pair(a,b)] == 0){ g[a].push_back(b); g[b].push_back(a); mp[make_pair(a,b)] = 1; } } int flag = 0; for(int i=0;i<26;i++){ if(g[i].size() > 2){ cout<<"NO"<<endl; flag = 1; break ; } } if(flag == 1){ continue ; } for(int i=0;i<26;i++) { if(!vis[i] && g[i].size() < 2){ dfs(i); } } if(ans.length() == 26){ cout<<"YES"<<endl; cout<<ans<<endl; }else{ cout<<"NO"<<endl; } } return 0; }
D:
题面:
给出一个书包的容量,给出n个盒子,每个盒子都是2的次幂,每个盒子都可以平均分成2部分,每部分都是原来的一半,问你最少需要分几次使得盒子可以恰好装满书包?
solution:
看到了2的次幂,就想到了二进制,如果所有盒子加起来小于容量,输出-1,否则肯定有解,下面考虑二进制贪心,将每一个盒子转成二进制,记录每一个位置上的数,从低位相比,如果该为为0,但是书包容量该为为1,那肯定就要去高位借一个1~按照这个思路,如果有两个或以上,记得进位
std:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 100005; ll a[maxn]; ll b[100],c[100]; void init() { memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); } void solve() { ll n , m ,sum = 0; int ans = 0; cin>>n>>m; for(int i=1;i<=m;i++) { cin>>a[i]; sum += a[i]; ll x = a[i]; int j = 0; while(x){ if(x%2){ b[j] += 1; } j++; x /= 2; } } if(sum < n){ cout<<"-1"<<endl; return ; } ll x = n; int k = 0; while(x) { if(x%2) c[k] = 1; k++; x /= 2; } for(int i=0;i<60;i++) { if(c[i]){ if(!b[i]){ for(int j=i+1;j<60;j++){ if(b[j]){ b[j]--; int now = j; while(now != i){ now--; b[now]++; ans++; } b[now]++; break ; } } } b[i]--; } b[i+1] += b[i]/2; } cout<<ans<<endl; } int main() { int t; cin>>t; while(t--) { init(); solve(); } return 0; }