题目链接
有一些屋子,每个屋子最多容纳三个人,有三种人,内向人必须一个人一个屋,外向人必须三个人同时一个屋子,综合人随意(一个两个三个都可)
现在有 a a a 个内向人, b b b 个外向人, c c c 个综合人。 问最少需要多少个屋子才能满足所有人的要求,如果无论如何都不能满足那么就输出-1
我们很容易发现, 对于内向人,不会导致输出-1.因为给他们一人一个屋子即可。 对于综合人同样不会导致输出-1. 只有当外向人在引入几个综合人之后,仍然无法成为3的倍数时,会导致出现-1的情况。 换成代码语言即为$ b%3+c<3$
只要不是输出-1 的情况,我们的答案即为 a + ⌈ b + c 3 ⌉ a+ \lceil \frac{b+c}{3}\rceil a+⌈3b+c⌉
def solve():
pass
a,b,c = [int(x) for x in input().split()]
if b%3 != 0 and b % 3 + c < 3 :
print(-1)
return
print((b+c+2)//3+a)
return
###########
for _ in range(int(input())):
solve()
有两个烟花发射器, 第一个烟花发射器会每隔a分钟发射一个烟花,第二个烟花发射器会每隔b分钟发射一个烟花。
而每个烟花会在天空持续 m + 1 m+1 m+1分钟,即若烟花在 t t t时刻被点燃,那么在 t , t + 1 , . . . , t + n t,t+1,...,t+n t,t+1,...,t+n 时刻都被视为在天空中的时间。现在问天空中最多同时出现多少个烟花。
很明显,在刚开始时,A和B烟花会同时开始释放,此刻在 m + 1 m+1 m+1分钟内有可能放出最多的量的烟花。这段时间中,这两个发射器都在第1时刻放出了一个烟花, 之后的m分钟则会各自再放出 m a , m b \frac{m}{a} , \frac{m}{b} am,bm 个烟花。于是我们便知道了总数为 2 + m a , m b 2+\frac{m}{a} , \frac{m}{b} 2+am,bm
def solve():
pass
a,b,m = [int(x) for x in input().split()]
ans = 2
ans += (m)//a
ans += (m)//b
print(ans)
###########
for _ in range(int(input())):
solve()
现在有一些居民 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an 排成一条线,他们各自意愿要住在路的左边或者右边。你需要修建一条路,修在 a i a_i ai和 a i + 1 a_{i+1} ai+1的中间 i = 0 , 1 , . . , n − 1 , n i = 0,1,..,n-1,n i=0,1,..,n−1,n 并且要求你对于路两边的居民,满足意愿的居民数量都大于等于不满足意愿的居民数量。
在这前提下,你要尽可能地将路修在中间,即 ∣ n 2 − i ∣ |\frac{n}{2} - i| ∣2n−i∣ 尽可能地小。如果两个最小的 ∣ n 2 − i ∣ |\frac{n}{2} - i| ∣2n−i∣ 都满足,输出较小的那个。
可以使用前缀和来记录满足意愿在左边的数量,这样如果路修在了i的位置,那么满足条件的表达式即为 x − s u m [ x ] > = s u m [ x ] & & s u m [ n ] − s u m [ x ] > = n − x − s u m [ n ] + s u m [ x ] x-sum[x]>=sum[x] \&\& sum[n]-sum[x]>=n-x-sum[n]+sum[x] x−sum[x]>=sum[x]&&sum[n]−sum[x]>=n−x−sum[n]+sum[x]
我们直接枚举 ∣ n 2 − i ∣ |\frac{n}{2} - i| ∣2n−i∣ 的值,然后推算出两个 i i i , 分别判断是否满足情况。
def solve():
pass
n = int(input())
lst = [0]
lst += [int(x) for x in input()]
sum = [0]*(n+2)
ans = []
for i in range(1,n+1):
sum[i] = sum[i-1] + lst[i]
for x in range(0,n+1):
if x-sum[x]>=sum[x] and sum[n]-sum[x]>=n-x-sum[n]+sum[x]:
ans.append(x)
dis = ans
mn = 9999999
for i in range(len(ans)):
mn = min(mn,abs(n/2-ans[i]))
for i in range(len(ans)):
if(abs(n/2-ans[i]) == mn):
print(ans[i])
break
###########
for _ in range(int(input())):
solve()
同学A想插队 ,他前面有n个人, 他想要查到前 m m m人中 ,现在有两个数组 a , b a,b a,b 。若同学A从位置 y y y插队到位置 x x x那么他就需要支付 a x a_x ax的金币,以及给中间所有人 b i ( x < i < y ) b_i(xbi(x<i<y) 个金币。他可以选择插队多次。 问最少需要花费多少金币才能够插到前m的位置。
我们若最终想要插队到第i的位置,那么所有 i < j ≤ n i
def solve():
pass
n,m = [int(x) for x in input().split()]
a = [int(x) for x in input().split()]
b = [int(x) for x in input().split()]
c = []
for aa,bb in zip(a,b):
c.append(min(aa,bb))
ans = [0]*(n+1)
sum = [0]*(n+1)
for i in range(n-1,-1,-1):
sum[i] = sum[i+1] + c[i]
for i in range(n-1,-1,-1):
ans[i] = sum[i+1]+a[i]
print(min(ans[0:m]))
###########
for _ in range(int(input())):
solve()
安东要按照二分搜索来从p这个排列中找x这个数,然他没发现这个排列并不是有序的。因此他可能最终找不到x这个数,现在需要你至多进行两次交换,来使得安东按照二分查找后可以找到 x x x这个数。
二分策略如下:起初让 l = 1 , r = n + 1 l = 1,r = n+1 l=1,r=n+1
最终的 p l p_l pl即为答案
很无趣的题目,直接按照题目中给出的二分方法找到最终的错误答案,然后将他和x所在的位置进行交换即可。
def solve():
pass
n,x = [int(x) for x in input().split()]
lst = [0]
lst += [int(x) for x in input().split()]
l = 1;r = n + 1
p = 0
for i,y in enumerate(lst):
if y == x :
p = i
break
while(1):
if(r - l == 1):
break
m = (l+r)//2
if lst[m]<=x:
l = m
else : r = m
print(1)
print(p,l)
###########
for _ in range(int(input())):
solve()
有一些蘑菇,用一个数组v, v 1 , v 2 , . . , v n v_1,v_2,..,v_n v1,v2,..,vn 表示每个蘑菇的价值。现在你可以采摘其中一些蘑菇,来获得蘑菇总数乘以采摘蘑菇中最小价值 的总价值。接下来还有一个排列p, p 1 , p 2 , . . . , p n p_1,p_2,...,p_n p1,p2,...,pn ,并且若你采摘了k个蘑菇,那么下标为 p 1 , p 2 , . . , p k − 1 p_1,p_2,..,p_{k-1} p1,p2,..,pk−1 的蘑菇的价值就会变为0,也就是说你将不能采摘这些蘑菇。
问可采摘的最大价值是多少
这场出现好多很无趣的题目,
使用一个标记数组 b a ba ba记录哪些蘑菇不允许再采摘(一共三个状态, b a [ i ] = 0 ba[i]=0 ba[i]=0表示可以采摘, b a [ i ] = 1 ba[i]=1 ba[i]=1表示不允许采摘他了, b a [ i ] = 2 ba[i]= 2 ba[i]=2表示被采摘过了。直接枚举采摘的数量,因为我们枚举的采摘数量越来越多,所以被ban掉的蘑菇只会越来越多。我们贪心地选择未被ban的蘑菇中,最大的那些即可。并且选择的这些蘑菇,同样可以在上一步所选中扩展而来,于是可以在 O ( n l o g n ) O(nlogn) O(nlogn)的排序过后就可以在 O ( n ) O(n) O(n) 的复杂度下选出答案。
代码解释可以看代码中的注释
#include
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define rep(i,l,r) for(int i = l;i<=r;i++)
#define per(i,r,l) for(int i = r;i>=l;i--)
const int INF = 0x3f3f3f3f3f3f3f3f;
typedef pair<int,int> PII;
void solve(){
int n ;
cin>>n;
vector<int> v(n+5);
rep(i,1,n) cin>>v[i];
vector<int> p(n+5);
rep(i,1,n) cin>>p[i];
vector<PII> node;
for(int i = 1;i<=n;i++){
node.push_back({v[i],i});//将蘑菇和原始序号绑定
}
sort(node.begin(),node.end());reverse(node.begin(),node.end()); //升序排序
vector<int> ba(n+5);//ba数组
int ans = -1;//最终答案
int ansc = 0;//answer count最终答案要采摘的数量
int mn = 0;//min,较小值
int nowp = 0;//轮到采摘哪个蘑菇了
int nowc = 0;//现在采摘了多少个蘑菇了
for(int cnt = 1;cnt <= (n+1)/2;cnt++){//最多选择(n+1)/2个蘑菇
if(ba[p[cnt-1]] == 2){//如果之前有蘑菇被采摘,后来被ban了,那么应该扔掉它
nowc --;//即将nowc减一。(扔掉它之后一定不影响最小值,所以不需要更改其他变量)
}
ba[p[cnt-1]] = 1;//ban掉这一轮的蘑菇
while(nowp<n && nowc < cnt){//选取蘑菇直到足够cnt个
if(ba[node[nowp].second] == 1){//如果当前蘑菇被ban了就换下一个
nowp++;continue;
}
mn = node[nowp].first;//当前的值一定比mn原先的更小,所以直接赋值即可
nowc++;
if(ans<mn*nowc){//更新答案
ans = mn*nowc;
ansc = nowc;
}
ba[node[nowp].second] = 2;//这个蘑菇采摘过了
nowp++;
}
}
cout<<ans<<" "<<ansc<<endl;//输出答案
}
signed main(){
int T = 1;
cin>>T;
while(T--){
solve();
}
return 0;
}