A. Setting up Camp
题意:给你a,b,c,a表示独居的人的个数,b表示可以同居的人的个数,但是必须要一屋子三个人,c表示可以两个人一起住也可以三个人一起住的人数,问最少需要几间屋子?
题解:先看a,a有多少人就需要多少间屋子,再看b,如果c的人数无法和b凑成3的倍数,那么一定是无解,其他的情况就是让c和b凑出最大的3的倍数,剩下的c最多组成一个屋子,得解。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e6 + 7 ;
const int mod = 998244353 ;
inline ll read() {
ll x = 0, f = 1 ;
char c = getchar() ;
while (c > '9' || c < '0') {
if (c == '-')
f = -1 ;
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
bool vis[maxn] ;
ll t , n , d , k , a[maxn] , b[maxn] , sum[maxn] , Sum[maxn] ;
void solve(){
n = read() ;
d = read() ;
k = read() ;
ll ans = n ;
ll res = (d + 3 - 1) / 3 ;
res = res * 3 ;
res = res - d ;
if(k >= res){
ll Ans = (k + d) / 3 ;
Ans = Ans * 3 - d ;
// cout << Ans << endl ;
cout << ans + ((k + d) / 3ll) + ((k - Ans) > 0 ? 1 : 0) << endl ;
return ;
}
else{
cout << -1 << endl ;
}
}
int main(){
t = read() ;
while(t --){
solve() ;
}
return 0 ;
}
B. Fireworks
题意:给你a , b , c ,一共有两种烟花,第一种每隔a分钟发射一次,第二种每隔b分钟发射一次,问找到一个区间满足,问找到一个区间能同时看到最多的烟花数量是多少?
题解:很明显,从开始,然后再看c分钟能放多少个烟花即可,答案就是。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e6 + 7 ;
const int mod = 998244353 ;
inline ll read() {
ll x = 0, f = 1 ;
char c = getchar() ;
while (c > '9' || c < '0') {
if (c == '-')
f = -1 ;
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
bool vis[maxn] ;
ll t , n , d , k , a[maxn] , b[maxn] , sum[maxn] , Sum[maxn] ;
void solve(){
n = read() ;
d = read() ;
k = read() ;
cout << 2ll + (k / n) + (k / d) << endl ;
}
int main(){
t = read() ;
while(t --){
solve() ;
}
return 0 ;
}
C. Left and Right Houses
题意:给你一个字符串包含0和1,要建设一条公路在x屋子之后,1表示该屋子主人想在公路的右边居住,0表示该屋子主人想在公路的左边居住,公路尽量建设在中心地段,问道路左边满足的人数和道路右边满足的人数都大于该区段的x/2上取整的坐标是多少,如果答案相同,取小坐标。
题解:看到n个数据范围,那么很容易想到贪心,先将坐标设置在0点,统计出人数,然后每次向右移动,如果说为1,那么右边的人数就减一,如果是0,那么左边的人数就加一,统计出所有满足的答案,然后再找到离市中心最近的坐标尽量小的答案即可。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e6 + 7 ;
const int mod = 998244353 ;
inline ll read() {
ll x = 0, f = 1 ;
char c = getchar() ;
while (c > '9' || c < '0') {
if (c == '-')
f = -1 ;
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
bool vis[maxn] ;
char s[maxn] ;
ll t , n , d , k , a[maxn] , sum[maxn] , Sum[maxn] ;
double b[maxn] ;
void solve(){
int cnt = 0 ;
n = read() ;
scanf("%s" , s + 1) ;
ll zuo = 0 , you = 0 ;
for(int i = 1 ; i <= n ; i ++){
if(s[i] == '1'){
you ++ ;
}
}
if(you >= (n + 2 - 1) / 2){
b[++ cnt] = 0 ;
}
for(int i = 1 ; i <= n ; i ++){
if(s[i] == '1'){
you -- ;
}
if(s[i] == '0'){
zuo ++ ;
}
ll res = i ;
ll Res = (n - i) ;
if(zuo >= (res + 2 - 1) / 2 && you >= (Res + 2 - 1) / 2){
b[++ cnt] = i ;
}
}
// for(int i = 1 ; i <= cnt ; i ++){
// cout << b[i] << " " ;
// }
// cout << endl ;
if(n % 2 == 1){
double mid = n / 2.0 ;
ll rt = n ;
double Min = INT_MAX ;
for(int i = 1 ; i <= cnt ; i ++){
double res = abs(b[i] - mid) ;
if(res < Min){
Min = res ;
rt = b[i] ;
}
if(res == Min){
rt = min(rt , (ll)b[i]) ;
}
}
cout << rt << endl ;
}
else{
double mid = (n / 2.0) ;
ll rt = n ;
double Min = INT_MAX ;
for(int i = 1 ; i <= cnt ; i ++){
double res = abs(b[i] - mid) ;
if(res < Min){
Min = res ;
rt = b[i] ;
}
if(res == Min){
rt = min(rt , (ll)b[i]) ;
}
}
cout << rt << endl ;
}
}
int main(){
t = read() ;
while(t --){
solve() ;
}
return 0 ;
}
D. Seraphim the Owl
题意:假设你是David,你是后来的,但是前面有n个人,每个人有两个属性和,假设你当前的位置是i,你可以和交换,但是你需要花费,你最后最大的位置是k,问你最小的花费是多少?
题解:这很明显是个贪心问题,在k之后的人你选择即可,到k的时候,你就得需要注意,如果说当前的的,那么就可以继续往前取,我就在这里wa了一发!所以只需要注意最后再从k枚举到2,看看最小的答案是多少,累加即可。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e6 + 7 ;
const int mod = 998244353 ;
inline ll read() {
ll x = 0, f = 1 ;
char c = getchar() ;
while (c > '9' || c < '0') {
if (c == '-')
f = -1 ;
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
bool vis[maxn] ;
char s[maxn] ;
ll t , n , d , k , a[maxn] , Sum[maxn] , b[maxn] , c[maxn] ;
void solve(){
int cnt = 0 ;
n = read() ;
k = read() ;
for(int i = 1 ; i <= n ; i ++){
a[i] = read() ;
}
for(int i = 1 ; i <= n ; i ++){
b[i] = read() ;
}
for(int i = 1 ; i <= n ; i ++){
if(a[i] == b[i]){
c[i] = 1 ;
}
if(a[i] > b[i]){
c[i] = 1 ;
}
if(a[i] < b[i]){
c[i] = 0 ;
}
}
ll sum = 0 , ans = 0 ;
for(int i = n ; i >= 1 ; i --){
if(i == k){
ll Ans = sum + a[i] ;
for(int j = k ; j >= 2 ; j --){
if(sum + b[j] + a[j - 1] < Ans){
Ans = sum + b[j] + a[j - 1] ;
}
sum = sum + b[j] ;
}
ans = ans + Ans ;
break ;
}
if(c[i] == 1){
sum += b[i] ;
}
else{
ans = ans + sum + a[i] ;
sum = 0 ;
}
}
cout << ans << endl ;
}
int main(){
t = read() ;
while(t --){
solve() ;
}
return 0 ;
}
E. Binary Search
题意:给你一个序列,满足所有数字出现一次且不重复,给你一个数字k,你需要用二分查找来使最后的a[l] == k,二分查找的过程是这样的,先让, 每次取,如果,那么,要不然,。你可以有两次修改数组的机会,,问操作是什么,不需要考虑最小次数。
题解:这种题一般都是有通解的,我们发现,假设第一次的中间值也就是的值不是k,那么直接进行二分查找找到的最后的值和k值所在的位置交换,就可以满足题意,那如果说怎么办,其实也很简单,将这个值换到坐标n就可以了,就可以满足答案。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e6 + 7 ;
const int mod = 998244353 ;
inline ll read() {
ll x = 0, f = 1 ;
char c = getchar() ;
while (c > '9' || c < '0') {
if (c == '-')
f = -1 ;
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
bool vis[maxn] ;
char s[maxn] ;
ll t , n , d , k , a[maxn] , Sum[maxn] , b[maxn] , c[maxn] ;
void solve(){
n = read() ;
k = read() ;
vector < pair < ll , ll > > q ;
for(int i = 1 ; i <= n ; i ++){
a[i] = read() ;
}
for(int i = 1 ; i <= n ; i ++){
b[a[i]] = i ;
}
if(b[k] != n){
q.push_back({b[k] , n}) ;
swap(a[b[k]] , a[n]) ;
}
ll l = 1 , r = n + 1 ;
while(r - l != 1){
ll mid = (l + r) / 2ll ;
if(a[mid] <= k){
l = mid ;
}
else{
r = mid ;
}
}
if(a[l] != k){
q.push_back({l , n}) ;
}
cout << q.size() << endl ;
for(auto it : q){
cout << it.first << " " << it.second << endl ;
}
}
int main(){
t = read() ;
while(t --){
solve() ;
}
return 0 ;
}
喜欢作者的记得点赞收藏加关注哦~