题目简述
波利卡普在由 $n$ 名学生(包括他自己)组成的小组中学习,编号为 $1$ 到 $n$,波利卡普的编号始终是 $1$。他们都在社交网络上注册,每个学生都有一个值 $a_i$,表示第 $i$ 名学生每天能发送的最大信息数。
清晨,波利卡普知道了一个重要消息,他认为有必要通过私人消息紧急通知所有组员。
您的任务是制定一个使用私人信息的计划,以便使
- 学生 $i$ 发送的信息数不超过 $a_i$。
- 所有学生都知道重要消息(最初只有波利卡普知道)。
- 学生只有在自己知道的情况下才能通知其他学生。
找到任意一种满足上述要求的使用私人消息的方法。
题目分析
如果一个同学要通知其他人,他一定会通知还能通知其他人且 $a_i$ 尽可能大的人,我们需要模拟上述贪心策略。
具体而言,我们可以先将 $2$ 到 $n$ 从大到小排序,枚举每一个 $i$,同时维护一个 $r$,表示 $1$ 到 $r$ 的人已经通知过了,每次使 $r \leftarrow r+a_i$,表示第 $i$ 个人通知第 $r+1$ 到 $r+a_i$ 的人。如果 $r \geq n$ 就结束。如果 $r<i$,那就说明前面的人不能通知到第 $i$ 个人,报告无解。用这种类似双指针的方法实现就可以了。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define random(a,b) (rand()%(b-a+1)+a)
#define se second
#define fi first
#define pr pair<int,int>
#define pb push_back
#define ph push
#define ft front
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,a,b) for(int i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof a)
const int N=201;
int n,r=1,cnt;
pr a[N],vis[N];
bool cmp(pr x,pr y)
{
return x.fi>y.fi;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
For(i,1,n)
{
cin>>a[i].fi;
a[i].se=i;
}
sort(a+2,a+1+n,cmp);
For(i,1,n)
{
if(r<i)
{
cout<<-1;
return 0;
}
For(j,r+1,min(r+a[i].fi,n))
{
vis[++cnt]={a[i].se,a[j].se};
}
r+=a[i].fi;
if(r>n) break;
}
cout<<cnt<<"\n";
For(i,1,cnt)
{
cout<<vis[i].fi<<" "<<vis[i].se<<"\n";
}
return 0;
}
标签:pr,About,769B,int,题解,波利,卡普,fi,define
From: https://www.cnblogs.com/zhuluoan/p/18199302