B - National Project
题意: 有一群工人在铺沥青,在好日子的时候铺出来是高质量的,现在有n段路,每天铺一段,好日子g坏日子b,只要铺出来一半的路是高质量的就行,问最少多少天能铺完。
题解: 直接算利用好日子会不会出,如果刚好就不用算后面的b,否则算上b之后加上剩余的(还是看代码比较直观吧)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std ;
typedef long long ll ;
int main(){
int t; scanf("%d",&t) ;
while(t--){
ll n,g,b; scanf("%lld%lld%lld",&n,&g,&b) ;
ll ans ;
ll x=(n+1)/2 ;
if(x%g==0){
ans = x/g*(g+b)-b ;
}
else{
ans = x/g*(g+b)+x%g ;
}
printf("%lld\n",max(ans,n)) ;
}
return 0 ;
}
C. Perfect Keyboard
题意: 给出一串密码,输出26个小写字母,要求按密码的时候密码的字母都相邻
题解: 初始化pos=30,ans[pos]==s[0] ,然后遍历放入,左右放。
①、如果当前字母访问过,则查看pos位置左右是否等于当前字母s[i]=ans[pos-1]
|| s[i]==ans[pos+1] .
②、如果当前字母没有访问过,则看pos位置的左右哪边为空就放入,pos也要移动到当前位置
输出ans中的字母,然后没有访问过的直接输出即可。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
using namespace std ;
typedef long long ll ;
bool vis[26] ;
char ans[100] ;
void solve(string s){
memset(vis,false,sizeof(vis)) ;
memset(ans,0,sizeof(ans)) ;
int pos=30 ;
ans[pos]=s[0] ,vis[s[0]-'a']=true ;
for(int i=1 ; i<s.length() ; ++i){
int t=s[i]-'a' ;
if(vis[t]){
if(s[i]==ans[pos-1]) --pos ;
else if(s[i]==ans[pos+1]) ++pos ;
else{
cout <<"NO"<<endl ;
return ;
}
}
else{
if(!ans[pos-1]) --pos ;
else if(!ans[pos+1]) ++pos ;
else{
cout <<"NO" <<endl ;
return ;
}
vis[t]=true ;
ans[pos]=s[i] ;
}
}
cout <<"YES"<<endl ;
for(int i=0 ; i<100 ; ++i){
if(ans[i]>='a'&&ans[i]<='z') cout<<ans[i] ;
}
for(int i=0 ; i<26 ; ++i)
if(vis[i]==0) cout<<(char)('a'+i) ;
cout <<endl ;
}
int main(){
int t; cin>>t ;
while(t--){
string s; cin>>s ;
solve(s) ;
}
return 0 ;
}
D - Fill The Bag(二进制)
题意: 给出n,和长度为m的数组,数组内的输都是2的幂次方,要用数组内的数凑成n,低位可以凑成高位,高位可以拆成低位,问拆高位的最少次数是多少。
题解: 将数组内的数转化为二进制,然后和转化成二进制的n进行计算,具体看图解和代码。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std ;
typedef long long ll ;
const int N=60 ;
int a[N] ;
ll n,m ;
int bit(ll x){
int cnt=0 ;
while(x>1){
x>>=1 ;
++cnt ;
}
return cnt ;
}
void solve(){
int cnt=0 ; //分解次数
for(int i=0 ; n>0 ; ++i){
if(n&1){
if(a[i]>0) a[i]-- ;
else{
for(int j=i+1 ; j<60 ; ++j){//找不为0的高位分解
if(a[j]){
--a[j] ; int k=j ; //分解高位
while(k!=i){ //逐位分解
++cnt ;
a[--k]++ ;
}
a[k] ++ ;
break ;
}
}
a[i]-- ;
}
}
a[i+1]+=a[i]/2 ; //用不到的低位可以凑成高位
n >>= 1 ;
}
printf("%d\n",cnt) ;
}
int main(){
int t; scanf("%d",&t) ;
while(t--){
scanf("%lld%lld",&n,&m) ;
ll x ,sum=0 ;
memset(a,0,sizeof(a)) ;
for(int i=0 ; i<m ;++i) scanf("%lld",&x),sum+=x, ++a[bit(x)] ;
if(sum<n){
printf("-1\n") ;
continue ;
}
solve() ;
}
return 0 ;
}