Codeforces1260D
给出m个士兵,每个士兵有迅捷值ai,士兵可以通过危险值不大于他的陷阱,给出k个陷阱,每个陷阱有位置l,失效的位置r和危险值d,给出t秒从0走到n+1,求最多带几个士兵过去
#include <bits/stdc++.h>
using namespace std;
const int maxn=201000;
int m,n,k,t;
int ai[maxn];
struct node{
int li,ri,wi;
};
node sum[maxn];
bool cmp(node n1,node n2){
return n1.li<n2.li;
}
bool scmp(int a,int b){
return a>b;
}
void init(){
scanf("%d%d%d%d",&m,&n,&k,&t);
for(int i=1;i<=m;i++) scanf("%d",&ai[i]);
sort(ai+1,ai+m+1,scmp);
for(int i=1;i<=k;i++) scanf("%d%d%d",&sum[i].li,&sum[i].ri,&sum[i].wi);
sort(sum+1,sum+k+1,cmp);
}
bool check(int mid)
{
if(mid==0) return true;
int res=0,l=-1,r=-1;
for(int i=1;i<=k;i++)
{
if(sum[i].wi<=ai[mid]) continue;
if(l==-1)
{
l=sum[i].li;
r=sum[i].ri;
continue;
}
if(sum[i].li<=r)
r=max(r,sum[i].ri);
else
{
res+=(r-l+1);
r=sum[i].ri;
l=sum[i].li;
}
}
if(l!=-1) res+=(r-l+1);
return res*2+(n+1)<=t;
}
void solve(){
int lb=0,rb=m,ans=1;
while(lb<=rb){
int mid=(lb+rb)/2;
if(check(mid))
{
ans=mid;
lb=mid+1;
}
else rb=mid-1;
}
printf("%d\n",ans);
}
int main(){
init();
solve();
return 0;
}
对题目的细节没有处理好,导致浪费时间,有个注意点是自己可以单独行动到r使陷阱失效,但士兵不能单独行动且选中的所有士兵要一起,因此每遇到一个有士兵不能通过陷阱之前,自己和士兵在同一位置,然后自己单独行动到陷阱失效的位置(前提是这个r没有踩过)再回来,路程要乘2,这就是代码中的res乘2,n+1是自己和士兵一起走过的距离;这个题目还运用了贪心的思想,在决定一个陷阱要不要亲自过去踩的时候,先判断带上的最小的士兵能否直接通过,不能则自己去踩,l,r表示自己走的起点与返回点,这时要走的距离为(r-l+1),但是为了达到贪心的目的,不能直接加到res上,还需要计算下一个陷阱是否也需要这样,如果也需要,再判断第二个陷阱的位置与r的关系,大于r则加到res里,并把l,r更新为第二个陷阱的,小于等于r则可以贪心一次踩多个陷阱,因为 /多个陷阱的单次来回的路程总和 / 必定大于 / 一次走最远的陷阱的失效位置使走过的陷阱失效的路程(/是断句)之后在对时间判断;最后一个关键性的问题士兵数量的选择,将士兵按值降序排之后,注意到带前 i +1个的时间肯定大于等于带前 i 个的,具有单调性,因此可以对士兵人数使用二分法来查找。
Codeforces1257D
给出n个怪兽,每个怪兽有一个力量值,给出m个英雄,每个英雄有力量值可以打过不大于他的怪兽,有耐力值表示每天最多可以打怪兽的数量,每天一个英雄,问最少几天可以打完
#include<bits/stdc++.h>
using namespace std;
const int MAX_N=200005;
int a[MAX_N];//大于等于i的endurance里power的最大值
int m[MAX_N];
int main(){
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d",&n);
for(int j=0;j<=n;j++)
a[j]=m[j]=0;
for(int j=1;j<=n;j++)
scanf("%d",&m[j]);
scanf("%d",&m);
for(int j=1;j<=m;j++)
{
int p,s;
scanf("%d%d",&p,&s);
a[s]=max(a[s],p);
}
for(int j=n-1;j>=0;j--)
a[j]=max(a[j+1],a[j]);
int pos=1,cnt=0;//第pos个怪物
while(pos<=n){
cnt++;
int s=0,maxp=m[pos];//今天可以向前推进ans个怪物
while(maxp<=a[s+1]&&pos<=n)
{//如果可以向前推进
s++;
pos++;
maxp=max(maxp,m[pos]);
}
if(s==0) break;
}
printf("%d\n",pos<=n?-1:cnt);
}
return 0;
}
因为每天只可以派一个英雄,所以耐力值相同的情况下,优先选择攻击力高的,用桶排序的思想选,最终得到每个耐力值下的最高攻击力,贪心的关键在于对耐力值贪心,每多判定一个,就找耐力值+1的最高攻击力能否打过,不能就下一天。
CodeForces 1249D2 *
给出n个闭区间,问去掉几个可以使每个点覆盖的区间小于等于k
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e5+10;
int n,k;
struct Node
{
int y;
int idx;
};
bool operator<(Node a,Node b)
{
if(a.y!=b.y)
return a.y<b.y;
return a.idx<b.idx;
}
vector<Node> g[N];
vector<int> ans;
int main()
{
int x,y;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
Node p;
scanf("%d%d",&x,&y);
p.y=y;
p.idx=i;
g[x].push_back(p);
}
set<Node> s;
for(int i=1;i<N;i++)
{
while(s.size()&&(*s.begin()).y<i)
s.erase(*s.begin());
for(int j=0;j<g[i].size();j++)
s.insert(g[i][j]);
while(s.size()>k)
{
ans.push_back((*s.rbegin()).idx);
s.erase(*s.rbegin());
}
}
printf("%d\n",ans.size());
int len=ans.size();
for(int i=0;i<len;i++)
{
printf("%d%c",ans[i],i==len-1?'\n':' ');
}
return 0;
}