题意:第一行给定n个点和m条绳子,第二行是点的位置(从小到大排列),第三行是绳子的长度。问能不能把所有的绳子都连进去(绳子的长度>=点之间的距离才可以连,且相同的两个点之间不能连两条绳子)。
思路:
贪心,n个点共可以连n*(n-1)/2条边,如果绳子数量大于这些就no
维护一个最小堆
然后先遍历一遍把相邻两点的距离放入堆中
越短的绳子肯定要对应距离越小的边,我们从小到大遍历绳子,每次找出里面最短的边,与当前遍历到的的绳子长度进行比较,如果当前遍历到的绳子比目前能连的最短的边的长度还小,那么肯定不能满足题目要求,直接跳出,否则的话,把目前的l与r右边的一个组成的距离放入堆中,进行下一次循环,直到遍历完所有绳子。如果能遍历完,那么满足了要求。
#include<iostream>
#include<set>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=5e5+5;
struct node{
int l,r,val;
bool operator < (const node a) const{
return a.val<val;
}
};
int a[maxn],s[maxn],n,m;
bool solve()
{
if(m>n*(n-1)/2)
return false;
priority_queue<node> q;
for(int i=0;i<n-1;i++)
q.push(node{i,i+1,a[i+1]-a[i]});
int cnt=0;
while(cnt<m)
{
node temp=q.top();
q.pop();
int l=temp.l,r=temp.r,val=temp.val;
if(s[cnt++]<val)
return false;
if(r<n-1)
q.push(node{l,r+1,a[r+1]-a[l]});
}
return true;//忘了写 竟然疯狂RE
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<m;i++)
scanf("%d",&s[i]);
sort(a,a+n);
sort(s,s+m);
if(solve())
printf("yes");
else printf("no");
return 0;
}