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;
}
京公网安备 11010502036488号