浙江农林大学第二十六届程序设计竞赛

目录

Problem A. 乘法 (easy)

题解:

代码:

Problem B. Love and Pease

题意:

代码:

Problem C. 来不及了,就这个吧

题意:

代码思路:

代码:

Problem F. 学术不端(easy)

题意:

代码思路:

tips:

代码:

Problem H. 对拍

题意:

代码思路:

代码:


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;
}

  • 39
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值