​​​题目链接 B. Obtain Two Zeroes

题意应该很好理解

做法:

0=a-2*x1-x2-2*x3...

0=b-x1-2*x2-x3...

两式相加:a+b=3* x1-3* x2-3*x3....

很明显只有(a+b)%3==0才有答案。

看看极限情况:

0=a-2*x1-2*x2-2*x3;

0=b-x1-x2-x3;

那么a最多就是b的两倍,如果a大于b的两倍,那也是没有答案的。

#include<bits/stdc++.h>
using namespace std;
int a,b;
int main()
{
int _;cin>>_;while(_--)
{
cin>>a>>b;
if(a>b)swap(a,b);
if(b>2*a){
puts("NO");
continue;
}
if((a+b)%3==0){
puts("YES");
continue;
}
puts("NO");
}
}

C. Infinite Fence

题目大意

现有10100块木板需要涂漆,第x块如果是x是a的倍数,则涂一种颜色,是b的倍数,则涂另一种颜色。如果既是a又是b的倍数,那么两种颜色都可以涂;如果连续有k块板的颜色是一样的,则会被处死,问是否能避免被处死。

解析

  • 只需要验证小间隔在大间隔之间有没有连续的k个

若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。

那么我们取d=lcm。x=lcm/a就是一段lcm区间内相邻a的数量为x,y=lcm/b就是一段lcm区间内相邻b的数量为y。


若a<b   (k-1)*x+1>y就是可以逃避被处死

a   a     a      a

四个a,三个区间  所以是(k-1)*a+1   看k个连续的a的长度是否小于一个b的长度

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
return b? gcd(b,a%b):a;
}
int main()
{
int _;cin>>_;while(_--)
{
ll a,b,k;
scanf("%lld%lld%lld",&a,&b,&k);
if(a<b) swap(a,b);

ll lcm=a*b/gcd(a,b);

ll x=lcm/a,y=lcm/b;

if((k-1)*x+1<y) printf("REBEL\n");
else printf("OBEY\n");
}
}

D. A Game with Traps

阅读理解题

读了半天没读懂,然后去搜题意:

现在,你要带着t的时间内带着士兵到老板面前,你目前的可位置被视为0,老板的位置可被视为n+1;你有m个士兵,每个士兵都有对应的敏捷度,途中一共有k个陷阱,位于li处,当敏捷度低于di的士兵经过时会死亡,你不会受陷阱的影响,而且当你走到ri的位置时,可以解除第i个陷阱;每秒钟你最多只能走一个单位距离(向前或向后),士兵如果要前进,就必须和你同时前进,求最多能带几个士兵过关;

也就是说当你遇到一个陷阱的时候,你需要将士兵都呆着原地,你一个人只身的去前面拆炸弹,那么就是这个l,r区间内会走三次。。

也有这种情况:l1   l2  r1  r2这时候最优的走法就是拆r1继续拆r2,最优走法还是这些区间最多走三次。。

那么我们就可以二分士兵人数(按敏捷值排序),通过暴力经过炸弹拆除判断能不能带这些士兵在t时间内到达n+1

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int d[N],l[N],r[N],val[N],a[N];
int m,n,k,t;
bool valid(int mid)
{
ll res=0;
ll tmp=a[mid];
for(int i=0;i<=n+1;++i) d[i]=0;
for(int i=1;i<=k;++i){
if(val[i]>tmp) d[l[i]]++,d[r[i]+1]--;
}
ll sum=0;
for(int i=1;i<=n+1;++i){
sum+=d[i];
if(sum>=1) res++;
}
return 2ll*res+n+1<=t;
}
int main()
{
cin>>m>>n>>k>>t;
for(int i=1;i<=m;++i) scanf("%d",&a[i]);
for(int i=1;i<=k;++i){
scanf("%d%d%d",&l[i],&r[i],&val[i]);
}
sort(a+1,a+1+m);
int l=1,r=m;
int ans=0;
while(l<=r){
int mid=l+r>>1;
if(valid(mid)){
r=mid-1;
ans=mid;
}
else l=mid+1;
}
if(ans==0) printf("0\n");
else printf("%d\n",m-ans+1);
}

E. Tournament

这题题意很好懂,就是有点难想,看了别人的代码后顿悟了。。太妙了

因为我每到2^i次方就必须要贿赂一个,则必须要贿赂2^i~2^(i+1)中的最小值一个。因为涉及到锦标赛排序,那我贿赂了当前位置到2^(i+1)中最小的一个的时候2^(i-1)到2^(i)的人我都可以通过某种分配方案,使得,只需要贿赂最小的就可以晋级。。

很妙。

看代码很好懂:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=(1<<18)+10;
int a[N],vis[N],n;
struct node
{
int x;
bool operator <(const node &o) const{
return o.x<x;
}
};
int main()
{
cin>>n;
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
int id=1;
while(id<=n){
vis[id]=1;
id<<=1;
}

priority_queue<node>que;
ll ans=0;
for(int i=n;i>=1;--i){
que.push({a[i]});
if(a[i]==-1) break;
if(vis[i]==1){
ans+=que.top().x;
que.pop();
}
}
printf("%lld\n",ans);
}