A. Level Statistics
题意:
统计一个游戏的数据情况,p代表目前被玩的次数,d代表被通关的次数,每次玩可以通关或者不通关,或者当前还在玩结果未知。判断给出的记录是否合法。(1≤n≤100)
思路:
注意几点:玩的次数不能小于被通关的次数,玩的次数和通过的次数不能随着事件减小,每个时刻玩的次数的人数变化不能小于通关的人数变化。
代码:
#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
int p[100010],c[100010];
int main(){
int T;
cin>>T;
while(T--){
int n,f=1;
cin>>n;
for(int i=1;i<=n;++i){
cin>>p[i]>>c[i];
if(c[i]>p[i]||p[i]<p[i-1]||c[i]<c[i-1]) f=0;
if(c[i]-c[i-1]>p[i]-p[i-1]) f=0;
}
if(f) cout<<"YES
";
else cout<<"NO
";
}
return 0;
}
B. Middle Class
题意:
给出一个每个人的财富值和这个国家对于富人的定义x,现在可以把一些人的财富聚在一起然后平分,求让富人最多可以有多少。(1≤n≤10^5)
思路:
先把按财富排序,从大到小每加入一个人计算一下平均值,当平均值小于x时退出遍历,当前被加入的人数就是富人最多的数量
代码:
#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
double a[100010],sum[100010];
int main(){
int T;
cin>>T;
while(T--){
int n,x;
cin>>n>>x;
for(int i=1;i<=n;++i) cin>>a[i];
sort(a+1,a+1+n,greater<int>());
for(int i=1;i<=n;++i){
sum[i]=sum[i-1]+a[i];
}
int ans=0;
for(int i=1;i<=n;++i){
if(sum[i]/(i*1.0)>=x) ans=i;
}
cout<<ans<<endl;
}
return 0;
}
C. Circle of Monsters
题意:
有n个怪兽站成一个环,每个怪物的血量不同,你可以向每个怪物打一枪子弹造成1的伤害,当一个怪物的血量变成0时会死并对它的下一个怪物造成一个爆炸伤害(每个怪物的爆炸伤害也不同),求最少开多少枪可以消灭所有怪物。(2≤n≤300000)
思路:
首先我们可以确定一下每个怪物最少要被打多少枪,即它的血量减去它上一个怪物的爆炸伤害(小于0时表示最少可以打0枪),当对每个怪物都造成至少的伤害,那么再把任意一个怪物打死,那么所有的怪物都会被连续炸死,所以把剩余血量最少的怪物打死。
代码:
#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
LL a[300010],b[300010 ];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
for(int i=0;i<n;++i) scanf("%lld%lld",&a[i],&b[i]);
LL res=0;
for(int i=0;i<n;++i) {
LL t=b[(i-1+n)%n];
if(a[i]>t) res+=a[i]-t,a[i]=t;
}
LL mn=1e15;
for(int i=0;i<n;++i){
if(mn>a[i]) mn=a[i];
}
res+=mn;
printf("%lld
",res);
}
return 0;
}
D. Minimum Euler Cycle
题意:
给出一个n个点的图形,n个点之间都互相有两条方向相反的边,求按走的点编号字典序最小的顺序把所有边走一遍(不能走重边),求序列的l~r区间的走法。(2≤n≤10^5,r−l+1≤10^5)
思路:
举个例子,当n=5时:完整的遍历的序列是:12131415
232425
3435
45
1
。这个规律就很显然了,把没用序列一个个直接跳过,有用的区间滚一遍,时间复杂度是可以接受的。
代码:
#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
const int N=100010;
int a[N];
long long n,l,r,cnt;
void solve(int f){
for(int i=f+1;i<=n;++i){
cnt++;
if(cnt>=l&&cnt<=r) cout<<f<<" ";
cnt++;
if(cnt>=l&&cnt<=r) cout<<i<<" ";
}
}
int main(){
int T;
cin>>T;
while(T--){
cin>>n>>l>>r;
cnt=0;
long long f=1;
while(f<n){
if(cnt+(n-f)*2>=l&&cnt<=r)
solve(f);
else
cnt+=(n-f)*2;
f++;
}
if(++cnt<=r) cout<<1<<" ";
cout<<endl;
}
return 0;
}