本次练习主要尝试了三道题,原序的A B D; 时间不够,不然应该认真看看C题的,感觉如果认真看题的话应该能ac出来,D题浪费的时间太长了还没做出来,就有点不太明智。
A
题意:将每个数分成c份求c份数的平方和的最小值。
思路:看就知道让每个数接近平均值就好了
#include <iostream>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
int c, sum;
cin >> c >> sum;
int ans = ((sum / c + 1) * (sum / c + 1) * (sum % c));
ans = ans + ((c - sum % c) * (sum / c)) * (sum / c);
cout <<ans<<endl;
}
return 0;
}
B.
题意:给两个数,两个数每次可以分别减去x和2x或分别减去2x和x 进行多次这个操作后是否能同时等于零。
思路:我本来觉得就是两个数的比例在(1,2】这个区间内就都是可以的,然后发现不对,因为两个数分别减去2和1所以每次两个数减去的数之和都是3的倍数,所以两个数的和也必须是3的倍数,不然无论如何也不能同时为零。
#include<iostream>
using namespace std;
int main(){
int t;
int n,m;
cin>>t;
while(t--){
cin>>n>>m;
if(n<m) swap(n,m);
if(n>m&&n<=2*m&&(n+m)%3==0) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
C.
题意:给两个数R B R的倍数要涂红色,B的倍数涂蓝,公倍数则选择一个涂,问:是否能有连续k个砖涂相同的颜色
思路:先把两个数化简(除以公因数)如果两个数相等就一定可以obey,不相等就一定有一个大数和一个小数,连续的k个数一定就是那个小数,那么判定条件就出来了,在两个b之间是否可以有k个r 即(k-1)*r+1 < b -1
#include<iostream>
using namespace std;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
int t;
cin>>t;
while(t--)
{
ll r,b,k;
cin>>r>>b>>k;
if(r>b)
swap(r,b);
ll g=gcd(r,b);
r/=g,b/=g;
if(r==b)
{
cout<<"OBEY"<<endl;
}
else if(b-1<(k-1)*r+1)
cout<<"OBEY"<<endl;
else
cout<<"REBEL"<<endl;
}
return 0;
}
D.
题意:题意特别复杂(应该是我目前见过最复杂的),先给m个士兵,任务是带着m个士兵走到boss点,然后又有k个地雷,这k个地雷分别又危险度,地点,解除地雷地点(解除需要自己走到那个地点解除),然后给你一个最短时间t,你需要在t时间内走到boss的位置,问你最多能带几个士兵。
思路:我一眼就看出要用二分找最多要带几个士兵而且找的士兵一定是敏捷度最高的几个士兵,就是check(x)的时候确实有点复杂,根据mid确定最小敏捷度的士兵是多少敏捷度,用这个最小敏捷度确定所有要排的雷,再最后算总时间
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int m,n,k,t;
int a[N],vis[N],s[N];
struct node{
int u,v,p;
}b[N];
bool cmp(node a,node b){
return a.v<b.v;
}
bool cmpp(int a,int b){
return a>b;
}
bool check(int mid){
if(mid==0) return true;
int res=0,l=-1,r=-1;
for(int i=1;i<=k;i++){
if(b[i].p<=a[mid]) continue;
if(l==-1){ l=b[i].u;r=b[i].v;continue; }
if(b[i].li<=r){
r=max(b[i].v,r);
}else{
res+=(r-l+1);
r=sum[i].ri;l=sum[i].u;
}
}
if(l!=-1) res+=(r-l+1);
return res*2+(n+1)<=t;
}
int main()
{
int i;
cin>>m>>n>>k>>t;
for(i=1;i<=m;i++)
cin>>a[i];
sort(a+1,a+1+m,cmpp);
for(i=0;i<k;i++){
cin>>b[i].u>>b[i].v>>b[i].p;
}
sort(b,b+k,cmp);
int l=1,r=m;
while(r>=l){
int mid=(l+r)/2;
if(check(a[mid])){
l=mid+1;
}else{
r=mid-1;
}
}
for(i=r;i>=l-1;i--){
if(check(a[i])){
cout<<i<<endl;
break;
}
if(i==0){
cout<<0<<endl;
break;
}
}
return 0;
}
E
题意:一共有n个人,每个人有各自的ai值,每轮比赛两两对决,你可以安排比赛的分布,也可以用ai的钱贿赂第i个人来取得胜利,问最后最少一共要用多少钱能取得最后的胜利。
思路:本来几乎没思路,然后看了一下大佬的题解,看了个很精妙的方法,思路就是,如果不贿赂,那么你一定是第n个人,如果要贿赂一个人,那么你就是第n/2到n个人要贿赂俩就是n/4到n/2,要贿赂能够进下一场比赛中的一个即可,所以是贿赂用钱最少的那个。那么只需要每次判断是否是2的幂次,如果是,那么就是要在之后的人中至少要贿赂一个,那么每次都这样选择最优贿赂就行了。这个i&(i-1)能直接判断i是否是2的次幂。
真没想到,E题能用这么精简的思路,这么精简的代码能做出来。
#include<iostream>
using namespace std;
#define ll long long
const int N=1e6+5;
ll a[N];
multiset<ll>s;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
ll ans=0;
for(int i=n;a[i]!=-1;i--){
s.insert(a[i]);
if(!(i&(i-1))){
ans+=*s.begin();
s.erase(s.begin());
}
}
cout<<ans<<endl;
return 0;
}