Codeforces 769B News About Credit 题解
题目简述
波利卡普在由 \(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;
}

浙公网安备 33010602011771号