奋斗群群赛---5

奋斗群群赛—5

T1:Curriculum Vitae

题目位置:

T1位置所在

题意:

给你一个 0 1串,让你求出要删除多少的0或1 之后字符串变为前面都是0,后面都是1 的字符串?求出最大长度是多少?

AC代码:

#include <bits/stdc++.h>
using namespace std;
int a[105];
int main()
{
    int n,tot=0;
    cin>>n;

    for(int i=1; i<=n; i++)
        cin>>a[i];

    for(int i=1; i<=n; i++)
    {

        {
            int num=0,num0=0;
            for(int j=i; j<=n; j++)
                if(a[j]==1)
                    num++;
            for(int j=1; j<=i; j++)
                if(a[j]==0)
                    num0++;
            if(num0+num>tot) tot=num0+num;
        }
        //else tot++;
    }
    cout<<tot<<endl;
}

小反思:

即知道如果在某个点时记录了1进去,那么之后只会有1出现,不会有别的数出现啊!
所以可以1~n的i 然后头到i 到尾再判一次!

T2:Math Show

题目位置:

T2位置所在

题意:

有n个任务,每个都有k个子任务,完成第kj个子任务的时间为 ti,完成一个子任务得一分,而且完成了一个大任务则多得一分,让你求怎么做任务,让最后得到的点数变为最大,输出最大的值(贪心)!

AC代码:

#include <iostream>
#include <algorithm>
using namespace std;
const int N=50;
int time[N];
int main()
{
    int n,k,t,all=0,tot=0;
    cin>>n>>k>>t;

    for(int i=1; i<=k; i++)
    {
        cin>>time[i];
        all+=time[i];
    }
    sort(time+1,time+1+k);
    for(int i=0; i<=n; i++)
    {
        int m=t-i*all,ans=0;//±íʾ×öÁË 0~n µÄ´óÈÎÎñ m ΪʣϵÄʱ¼ä
        if(m<0) break;
        ans+=i*k+i;
        //cout<<ans<<" "<<m<<endl;
        for(int v=1; v<=k; v++)  //1~k µÄСÈÎÎñ ¿ªÊ¼½øÐÐÈûÂú
            for(int j=1; j<=n; j++)
            {
                if(j+i<=n&&m>=time[v])
                {
                    ans++;
                    m-=time[v];
                }
                if(j+i>n) break;
                if(m<time[v])
                    break;
            }
        if(ans>tot)tot=ans;
    }
    cout<<tot<<endl;
}

小反思:

利用一个循环,从1~n个大任务循环,做完i个任务之后就专心做小任务就好,输出了最大的情况来!

T3:Four Segments

题目位置:

T3位置所在

题意:

 给了你n个数字a1~n.在有3个整数delim0,delim1,delim2,将这一行的数据分成4份,可以分别记为区间 s1,s2,s3,s4.求s1-s2+s3-s4的最大值的代表数字delim0,delim1,delim2的值,只要输出一个就好了!

但是记住比如区间s的算法是sum(l,r) 从l加到r但是不包括r,包括了l!

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N=5005;
long long int a[N],s[N];
int main() {
    int n;
    scanf("%d",&n);
    long long int all=0;
    for(int i=0; i<n; i++) {
        cin>>a[i];
        all+=abs(a[i]);
    }

    s[0]=0;
    for(int i=1; i<=n; i++)
        s[i]=s[i-1]+a[i-1];

    long long int res=-9999999,delim0=-1,delim1=-1,delim2=-1;
    for(int i=0; i<=n; i++) {
        int d1,d2,d3;
        d2=i;
        d1=d3=d2;
        for(int j=0; j<=i; j++) if(s[j]>s[d1]) d1=j;
        for(int v=i; v<=n; v++) if(s[v]>s[d3]) d3=v;

        long long int tot;
        tot=s[d1]+s[d3]-s[d2];

        if(tot>res) {
            //cout<<s[i]<<" "<<s[j]<<" "<<s[v]<<" "<<s[n]<<endl;
            res=tot;
            delim0=d1;
            delim1=d2;
            delim2=d3;
        }
    }

    cout<<delim0<<" "<<delim1<<" "<<delim2<<endl;
//cout<<res<<endl;
    return 0;
}

小反思:

一开始就是开始算三重循环的算法来!结果会TLE哦,不过是一部成功的开始—所以将算法简化一点就是加上s[d1]+s[d3]-s[d2]的最大值,所以只要一个循环找s2,在从中找s1的max与s3的max就好了,然后看看能不能更新答案就好了!

T6:Random Query

题目位置:

T6题目位置

题意:

给出一个n个数字的数列a[1],…,a[n],f(l,r)表示使a[l],a[l+1],…,a[r]组成的新序列中的重复元素只保留一个后,剩下元素的数量(如果l>r,则在计算前先交换l和r)。从1-n中分别选出两个数字l和r(两个数字选时各自独立,每个数字选出1-n的概率相等),求f(l,r)的数学期望。

AC代码:

#include <bits/stdc++.h>
using namespace std;
int head[1111111]= {0};
int main()
{
    int n,x;
    cin>>n;
    long long int tot=-n;


    for(int i=1; i<=n; i++)
    {
        cin>>x;
        tot+=(long long int)(i-head[x])*(n-i+1)*2;
        head[x]=i;
    }
    printf("%.10lf\n",(double)tot/((double)n*n));
}

小反思:

一定要推公式,不然又会TLE的!所以我们

就考虑当前这个数对多少区间有贡献,那么肯定是跨越它的区间了,我们可以从反面来考虑,假设每个数对所有区间都有贡献,那么贡献为n*n ,没有跨越它的区间就是他的左面和右面.我们要考虑减掉这一部分,但是如果有重复数的话,那么未出现该数的区间就是所有
重复数的两两中间那一部分了,其余的部分都出现了该数,该数都有价值.
head[i]记录上一个一样的数据的位置

(i-head[x])*(n-i+1)*2

总结

1.学会推公式
2.多考虑边界情况
3.灵活考虑剪枝的情况,可以方便不会TLE!
4.学会将三重循环转化为二重循环或者一重,只要发现之间的联系就好!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值