目录
Problem A. 乘法 (easy)
题解:
签到题。注意开long long。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
ll a,b,c,d;
cin>>a>>b>>c>>d;
cout<<a*b*c*d<<endl;
return 0;
}
Problem B. Love and Pease
题意:
fruit在Love and Pease战队,战队共5人,每个人有自己的 KDA(kill,die,assit)。
KDA的计算公式:KDA=(kill+assit)/die。特别的,die==0时,KDA=+∞。
fruit分数的规则如下:
1.初始值为0。
2.如果Love and Pease战队获胜,fruit加上p分。如果fruit获得MVP,额外加p分。
3.如果Love and Pease战队战败,fruit扣q分,如果获得SMVP,则本场比赛不扣分。
4.fruit的分数到达100分后,不会再扣分。
5.fruit的分数不会小于0。
MVP的评判:
1.获胜。
2.KDA全队最高。可以并列。
SMVP的评判:
1.战败。
2.KDA全队最高。可以并列。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=105;
double MAX=999999.0;
int k[N],d[N],h[N];
double kda[N];
int killl=0,die=0,fruit=0,num=0;
double maxkda=0.0;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,p,q;
cin>>n>>p>>q;
for(int i=0;i<n;i++){
killl=0,die=0,num=0;
maxkda=0.0;
for(int j=0;j<5;j++){
cin>>k[j]>>d[j]>>h[j];
killl+=k[j];
die+=d[j];
if(d[j]==0){
kda[j]=MAX;
}
else{
kda[j]=1.0*(k[j]+h[j])/d[j];
}
}
map<int,double>mp;
for(int j=0;j<5;j++){
if(kda[j]>maxkda){
num=j;
maxkda=kda[j];
mp.clear();
mp[num]=maxkda;
}
else if(kda[j]==maxkda){
mp[j]=kda[j];
}
}
if(fruit>=100){
continue;
}
if(killl>=die){
fruit+=p;
if(mp.find(0)!=mp.end()){
fruit+=p;
}
}
else{
if(mp.find(0)==mp.end()){
fruit-=q;
if(fruit<0){
fruit=0;
}
}
}
mp.clear();
}
//cout<<fruit<<endl;
if(fruit>=100){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
return 0;
}
Problem C. 来不及了,就这个吧
题意:
小黄在做codeforces和atcoder的题集。codeforces有n题,atcoder有m题。他有自己的规则。给定了时间k,问他最多能做几道题目。
规则:
1.题目具有先后顺序,同一个题目集只能先做编号小的。
2.每次只会选择一个题单。
代码思路:
1.分别求出codeforces和atcoder做题时间的前缀和。前缀和包括当前题目做题目的时间。
2.在求前缀和时,求出只做当前题集能做的最大题数。
3.最大题数都为0时,输出0。
4.当有一方为0时,输出另一方的最大题解数。也可以采用二分遍历(多余了)。
5.两方都不为0时,我们遍历codeforces的题解,再对atcoder的前缀和进行二分查找,求得最大的题目数量。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5;
ll n,m,k;
ll cf[N],ac[N];
ll sumcf[N],sumac[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m>>k;
int poscf=0,posac=0;
for(int i=1;i<=n;i++){
cin>>cf[i];
if(i==1){
sumcf[i]=cf[1];
if(sumcf[i]<=k){
poscf=i;
}
}
else{
sumcf[i]+=sumcf[i-1]+cf[i];
if(sumcf[i]<=k){
poscf=i;
}
}
}
for(int i=1;i<=m;i++){
cin>>ac[i];
if(i==1){
sumac[i]=ac[1];
if(sumac[i]<=k){
posac=i;
}
}
else{
sumac[i]+=sumac[i-1]+ac[i];
if(sumac[i]<=k){
posac=i;
}
}
}
if(poscf==0&&posac==0){
cout<<"0"<<endl;
}
else if(poscf!=0&&posac==0){
cout<<poscf<<endl;
/*int l=1,r=poscf;//可以试试二分。
while(l<r){
int mid=(l+r)>>1;
if(sumcf[mid]<k){
l=mid+1;
}
else if(sumcf[mid]>k){
r=mid;
}
else{
cout<<mid<<endl;
return 0;
}
}
if(sumcf[r]>k){
cout<<r-1<<endl;
}
else if(sumcf[r]<=k){
cout<<r<<endl;
}*/
}
else if(poscf==0&&posac!=0){
cout<<posac<<endl;
/*int l=1,r=posac; //可以试试二分。
while(l<r){
int mid=(l+r)>>1;
if(sumac[mid]<k){
l=mid+1;
}
else if(sumac[mid]>k){
r=mid;
}
else{
cout<<mid<<endl;
return 0;
}
}
if(sumac[r]>k){
cout<<r-1<<endl;
}
else if(sumac[r]<=k){
cout<<r<<endl;
}*/
}
else{
int maxx=0;
for(int i=0;i<=poscf;i++){
ll sum=sumcf[i];
int l=1,r=posac;
int cc=i;
int flag=1;
while(l<r){
int mid=(l+r)>>1;
if(sum+sumac[mid]<k){
l=mid+1;
}
else if(sum+sumac[mid]>k){
r=mid;
}
else if(sum+sumac[mid]==k){
cc+=mid;
flag=0;
break;
}
}
//cout<<"l="<<l << " r="<<r<<endl;
if(flag){
if(sum+sumac[r]>k){
cc+=r-1;
}
else if(sum+sumac[r]<=k){
cc+=r;
}
}
maxx=max(cc,maxx);
}
cout<<maxx<<endl;
}
return 0;
}
Problem F. 学术不端(easy)
题意:
小黄现在有一个长度为 n 的序列,表示一批样本的实验数据。为了让实验结果看起来足够稳定,我们需要找到一个长度大于等于 2 的子段,使得该子段的方差最小,并告诉小黄这个最小的方差乘以子段长度平方的结果。
代码思路:
1.记录原始数据的前缀和。
2.记录原始数据的平方的前缀和。
3.n的范围较小,二层循环遍历,取出长度大于等于 2 的子段,通过前缀和之差求得总和,再求期望,再求方差。
4.当第一次求得方差的时候,求得ans,记录mans(序列长度)。
5.在线比较方差,如果较小,变换ans和mans。
tips:
1.注意double。
2.注意字段长度大于等于2。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e3+4;
int n;
double a[N];
double b[N];
double aqian[N];
double bqian[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
aqian[0]=0;
bqian[0]=0;
for(int i=1;i<=n;i++){
cin>>a[i];
aqian[i]=a[i]+aqian[i-1];
b[i]=a[i]*a[i];
bqian[i]=b[i]+bqian[i-1];
}
/*for(int i=1;i<=n;i++){
cout<<"a["<<i<<"]="<<a[i]<<endl;
}
for(int i=1;i<=n;i++){
cout<<"b["<<i<<"]="<<b[i]<<endl;
}
for(int i=1;i<=n;i++){
cout<<"aqian["<<i<<"]="<<aqian[i]<<endl;
}
for(int i=1;i<=n;i++){
cout<<"bqian["<<i<<"]="<<bqian[i]<<endl;
}*/
double ans;
int mans=0;
int flag=1;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
int m=j-i+1;
if(m==1)
continue;
double avaa=(1.0*aqian[j]-1.0*aqian[i-1])/m;
double avab=(1.0*bqian[j]-1.0*bqian[i-1])/m;
double res=(avab-avaa*avaa);
//cout<<"m="<<m<<" avaa="<<avaa<<" avab="<<avab<<" res="<<res<<endl;
if(flag){
ans=res;
mans=m;
flag=0;
}
else{
if(res<ans){
mans=m;
ans=res;
}
}
}
}
cout<<1.0*ans*mans*mans<<endl;
return 0;
}
Problem H. 对拍
题意:
有一个长度为 n 的序列 A。对于任意 i 均使得 Ai 之后的所有逆序对都小于 Ai。其中,某个逆序对小于 Ai 定义为逆序对的第二个成员小于 Ai。也可以换个说法,所有逆序对的第二成员都要小于逆序对之前所有的数,满足输出YES,否则输出NO。
代码思路:
1.n为1或2,无逆序对或是逆序对之前无数,直接输出YES。
2.n大于2时,初始化pos为更新最小值位置。记录minn为序列的第一个数a[1]。从第三个数遍历序列,找到逆序对的时候,比较minn和第二成员。
3.每次寻找逆序对的时候,在线更新minn,minn与a[pos++]进行比较。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e6+4;
int n;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
if(n==1||n==2){
cout<<"YES"<<endl;
}
else{
int minn=a[1];
int pos=1;
for(int i=3;i<=n;i++){
if(a[i]<a[i-1]){
if(a[i]>=minn){
cout<<"NO"<<endl;
return 0;
}
}
minn=min(minn,a[pos++]);
}
cout<<"YES"<<endl;
}
return 0;
}