点这里进入比赛
A. Robin Helps
题目及范围:
思路:直接模拟题目操作。钱超过k,就让累加进罗宾汉的钱袋里。如果遇到没钱的人,并且自己有钱,就赏一块钱。否则就跳过。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#define int long long
#define endl '\n'
using namespace std;
int n,k,m,t;
int num[200];
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
int ans=0;
int cnt=0;
for(int i=1;i<=n;i++) cin>>num[i];
for(int i=1;i<=n;i++){
if(num[i]>=k){
cnt+=num[i];
} else if(num[i]==0){
if(cnt>=1){//加判断条件,如果手里没钱就不接济穷人
cnt--;
ans++;
}
}
}
cout<<ans<<endl;
}
return 0;
}
B. Robin Hood and the Major Oak
题目及数据范围:
思路:注意到如果是偶数,必然为偶数。反之则必为奇数。依此化简题目。
最后的叶子数,就是最后k年的叶子的数量。同时我们易得生长的叶子数量必是一年奇数一年偶数的。那问题就变成了,求区间内长奇数片叶子的年份,是奇数还是偶数。因为无论k内长偶数片叶子的年份有几年,都是偶数。而奇数片叶子的年份如果是奇数,则总答案为奇数(奇+奇+奇=奇)。若为偶数年,总答案为偶数(奇+奇=偶)。总之就是求k年内长奇数片叶子的年份数量是奇还是偶就好啦。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
#define endl '\n'
using namespace std;
int n,k;
int t;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>n>>k;
int cnt=0;//奇数年的数量。
int l=max(1ll,n-k+1);//判断对答案有用的起始年。
if(l&1)//起始年是奇数年
if(k&1) cnt=k/2+1;//分长度为奇数和偶数分别求cnt。
else cnt=k/2;
else cnt=k/2;//起始年是偶数年,则cnt必等于k/2。
if(cnt&1) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
C. Robin Hood in Town
题目与数据范围:
思路:有超过一半的人的钱乘上两倍还比平均的钱少,罗宾汉就会出现。
首先,如果只有一个人或者两个人,不可能存在上述情况。所以直接输出-1即可。
既然提到“一半以上”我们可以先排序,找钱严格大于所有人的一半的第一个人。我们叫他mid。
我们的目标是让mid也不开心,这样在他前面的一半人保证也不开心。
我们这个人的钱数乘以2,得到“临界状态下的平均钱数”。
有了平均钱数,乘以人数n,得到“临界状态的总数”,叫它ans。
如果现在的钱的总和tot已经超过这个值,则不用加x就会满足情况,所以输出0。
否则,临界值与现在总和的差值,就是要加上的x的大小。
(注意:因为要严格大于num[mid],所以ans要再加上1,保证mid会不开心)
复杂度瓶颈在排序,总复杂度
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
#define endl '\n'
using namespace std;
int n,k;
int t;
int num[200005];
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>n;
int tot=0;//这个变量存原先数组的总和。
for(int i=1;i<=n;i++) cin>>num[i],tot+=num[i];
sort(num+1,num+1+n);//升序排序。
int midd=(1+n+1)>>1;//找mid的位置。
int ans=num[midd]*2;
ans*=n;//求目标值
if(n<=2) cout<<-1<<endl;
else if(tot>ans) cout<<0<<endl;
else cout<<ans+1-tot<<endl;//记得要+1。
}
return 0;
}
D. Robert Hood and Mrs Hood
题目及数据范围:
思路:每个任务的执行时间都是一个区间,我们很容易想到用差分数组实现区间修改,最后知道每一天有几个任务。
但实际上,一个工作能影响的时间,不只是l到r这几天。还有l前面的几天和r后面的几天。因为一次访问是持续d天的。只要有一天重叠,就被影响到了。
设开始日为 ,如果开始日 满足 ,那么这段工作将与访问重叠。因为访问是持续d天的。(最后一天与工作重叠也算)
因此我们这里差分的不是这个工作开始到结束的区间。意思是,起始时间在 内的一个访问,都会被这个工作所影响到。所以我们差分的范围要更大一些。
之后,我们再遍历一遍原数组,枚举起始日,找到工作贡献最多和工作贡献最少的那一天,就是答案。
如果 , 就让贡献影响日期改成1,防止溢出。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
#define endl '\n'
using namespace std;
int n,d,k,t;
int num[200005];
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>n>>d>>k;
for(int i=1;i<=k;i++){
int l,r;
cin>>l>>r;
l=max(1ll,l-d+1);//注意这里的l的意义不是任务的起始日期,是开始计算贡献的那一天。
num[l]++;num[r+1]--;//差分数组给区间增加贡献
}
for(int i=1;i<=n;i++) num[i]+=num[i-1];//前缀和还原成原数组
int p1=1;//妈妈来最合适的那一天
int p2=1;//兄弟来最合适的那一天
int maxx=-0xFFFFFFFFF;
int minn=0xFFFFFFFFF;
for(int i=1;i<=n-d+1;i++){//注意i的取值范围。i枚举的是开始访问的那一天
if(num[i]>maxx) p1=i,maxx=num[i];//更新找最大最小
if(num[i]<minn) p2=i,minn=num[i];
}
cout<<p1<<" "<<p2<<endl;
for(int i=0;i<=n+1;i++) num[i]=0;//多测一定要清空,不然会不幸。(((
}
return 0;
}