CF1887题解
CF1887A1
首先肯定的是,先把两个数组大到小排序
有两种思路:
- 因为b越大价值越大,a越小价值越大,所以用双指针对于每种b找到最大的对应的a
- 因为上述的贪心方法一定能调整成以下的贪心方法,保证不劣:将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]);
}

浙公网安备 33010602011771号