CF-Educational Codeforces Round 77 (Rated for Div. 2)(A-E题解)
A. Heating (水题)
大致思路:
因为是代价是平方,所以让每一个房间的大小平均即可,即最大和最小相差不超过一。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n;
int main()
{
//freopen("H:\\c++1\\in.txt","r",stdin);
//freopen("H:\\c++1\\out.txt","w",stdout);
ll c,sum;
scanf("%lld",&n);
while(n--){
scanf("%lld%lld",&c,&sum);
ll s=sum/c,yu=sum%c,ans=0;
//cout<<s<<" "<<yu<<endl;
for(int i=1;i<=min(c,sum);i++){
if(yu){
ans+=(s+1)*(s+1);yu--;
}else{
ans+=(s)*(s);
}
}
printf("%lld\n",ans);
}
return 0;
}
B. Obtain Two Zeroes (找结论)
大致思路:
首先观察到 \((0,0)\) 态是可行的,那么其可以转移到的状态也是可行的,由于是加上 \(,x,2x\) ,那么 \((a,b)\) 的 \(a+b\) 必然是 \(3\) 的倍数,而且可以知道较大数不能大于较小的数两倍,虽然这只是必要条件,还是不够严谨,但是能过。
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
//freopen("H:\\c++1\\in.txt","r",stdin);
//freopen("H:\\c++1\\out.txt","w",stdout);
int n,a,b;
scanf("%d",&n);
while(n--){
scanf("%d%d",&a,&b);
if((a+b)%3==0&&max(a,b)<=2*min(a,b)){
puts("YES");
}
else puts("NO");
}
return 0;
}
C. Infinite Fence (数学)
大致思路:
假设 \(r>b\) ,主要是判断在 \((m1*r,(m1+1)*r)\) 之中b的倍数最多出现多次。所以要找到一个 \(m*b\%r\) 的最小值,可以知道这个值就是 \(gcd(b,r)\) ,那么我们其实就是判断 \(gcd(b,r)+(k-1)*b\) 和 \(r\) 的关系就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
ll T,r,b,k;
int main()
{
//freopen("H:\\c++1\\in.txt","r",stdin);
//freopen("H:\\c++1\\out.txt","w",stdout);
scanf("%lld",&T);
while(T--){
scanf("%lld%lld%lld",&r,&b,&k);
if(r==b){ // 特判一个相等的情况,不够其实不用好像
puts("OBEY");continue;
}
if(r<b)swap(r,b);
if(r%b==0){
if(k*b<r){
puts("REBEL");
}else puts("OBEY");
continue;
}
ll g=gcd(r,b);
if(g+(k-1)*b<r){
puts("REBEL");
}else puts("OBEY");
}
return 0;
}
D. A Game with Traps (二分+贪心)
大致思路:
首先最容易想的二分带的人数,然后进行判断,重点是怎么判断。发现无论如何部队必然要走 \(n+1\)步,那么我们可以不用去管,那么对于两个雷 \((l_1,r_1),(l_2,r_2)\), 如果 \(l_2<=r_1\) ,那么最优的方法就是一次性走到 \(r_2\) 再回来带人,否则就正常模拟。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
int n,m,k,t;
struct node{
int l,r,d;
node(int a=0,int b=0,int c=0){l=a,r=b,d=c;}
}lei[N];
vector<node>tt;
bool cmp(node a,node b){
return a.l<b.l;
}
bool check(int x){
tt.clear();
int nl=a[x];
for(int i=1;i<=k;i++)if(lei[i].d>nl)tt.push_back(lei[i]);//有危险的雷
if(tt.size()==0)return 1;
int ans=n+1,mx=0,now=tt[0].l-1;//部队行动距离必然要为n+1
for(int i=0;i<int(tt.size());i++){
mx=tt[i].r;
int j=i+1;
while(j<int(tt.size())&&tt[j].l<=mx)mx=max(mx,tt[j].r),j++;//有交集
ans+=(mx-now)*2;
now=tt[j].l-1;//更新
i=j-1;
}
//cout<<x<<" "<<ans<<endl;
if(ans<=t)return 1;//比较
else return 0;
}
int main()
{
//freopen("H:\\c++1\\in.txt","r",stdin);
//freopen("H:\\c++1\\out.txt","w",stdout);
scanf("%d%d%d%d",&m,&n,&k,&t);
for(int i=1;i<=m;i++)scanf("%d",&a[i]);
sort(a+1,a+1+m);//按能力排序
reverse(a+1,a+1+m);//降序
for(int i=1;i<=k;i++){
scanf("%d%d%d",&lei[i].l,&lei[i].r,&lei[i].d);
}
sort(lei+1,lei+1+k,cmp);//按l排序
int ans=0,l=1,r=m;
while(l<=r){//二分
int mid=(l+r)/2;
if(check(mid)){
ans=mid;l=mid+1;
}else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
E. Tournament (贪心)
大致思路:
我们发现每一轮都会淘汰一些人,我们的贪心策略就是让力量大的人尽量淘汰更多的人,那么我们就可以减少花费,而且在 \(k\) 轮,对于前 \(2^k-1\) 个人我们就不能选择,因为他们必定淘汰,所以我们从后面开始,每次选择我们可以选择的人花费最小的就行。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=(1<<20);
int n;
int a[N];
int vis[N];
multiset<int>s;
int main()
{
/* freopen("H:\\c++1\\in.txt","r",stdin);
freopen("H:\\c++1\\out.txt","w",stdout);
*/ scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=0;(1<<i)<=n;i++)vis[(1<<i)]=1;
ll ans=0;
for(int i=n;i>=1;i--){
if(a[i]==-1)break;
s.insert(a[i]);
if(vis[i]){//选择可以选的代价最小的人
ans+=*(s.begin());
s.erase(s.begin());
}
}
printf("%lld\n",ans);
return 0;
}