CF1887题解

CF1887A1

首先肯定的是,先把两个数组大到小排序

有两种思路:

  1. 因为b越大价值越大,a越小价值越大,所以用双指针对于每种b找到最大的对应的a
  2. 因为上述的贪心方法一定能调整成以下的贪心方法,保证不劣:将b保留尽可能大的,a保留尽可能小的。这种二分来做,然后用贪心判断合法即可

CF1887A2

发现,只修改第一个数,最多能使答案+1,答案具有可二分性

因为我们本身就是拿二分来判断合法的,所以只需要知道序列的样子,就可以求出答案,序列也具有可check性

所以再套一个二分,即可

CF1887B

刚开始不知道一组边集可以重复使用,想了一个假做法,直到写完才发现假了,

然后休息了一会,回来一下就切了

考虑我们维护每个点最小能到达的时间,然后因为时间是一直变大的,所以满足三角形不等式,可以dij做

考虑每条边可以被访问的最小时间用二分来做就行了

点击查看代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first 
#define se second
using namespace std;
const int N=2e5+5,inf=1e9+5;
int n,t,k;
struct edge{
    int v,f;
};
vector<edge>e[N];
vector<int>bt[N];
int dis[N],a[N];
priority_queue<pii,vector<pii>,greater<pii> >q;
void dij(){
    for(int i=1;i<=n;i++){
        dis[i]=inf;
    }
    dis[1]=0;
    q.push({0,1});
    while(!q.empty()){
        int u=q.top().se;
        q.pop();
        for(auto i:e[u]){
            int v=i.v,f=i.f;
            auto w=lower_bound(bt[f].begin(),bt[f].end(),dis[u]+1);
            // for(int g:bt[f])  printf("%d ",g);
            // printf("\n%d %d %d %d\n",dis[u]+1,u,v,*w);
            if(w!=bt[f].end()&&*w<dis[v]){
                dis[v]=*w;
                q.push({dis[v],v});
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&t);
    for(int i=1;i<=t;i++){
        int m;
        scanf("%d",&m);
        for(int j=1;j<=m;j++){
            int u,v;
            scanf("%d%d",&u,&v);
            e[u].push_back({v,i});
        }
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++){
        scanf("%d",&a[i]);
        bt[a[i]].push_back(i);
    }
    dij();
    // for(int i=1;i<=n;i++){
    //     printf("%d\n",dis[i]);s
    // }
    if(dis[n]==inf)  dis[n]=-1;
    printf("%d\n",dis[n]);
}
posted @ 2025-09-09 14:36  daydreamer_zcxnb  阅读(11)  评论(0)    收藏  举报