div.3前六题题解

 A. Problemsolving Log

#include<iostream>
using namespace std;
int main()
{
    int t;cin>>t;
    while(t--)
    {
        int cnt[26]={0};
        int ans=0;
        int n;cin>>n;
        string a;cin>>a;
        for(int i=0;i<a.size();i++)
        cnt[a[i]-'A']++;//算出每一道题目用了多少时间
        for(int i=0;i<26;i++)
            if(cnt[i]>=i+1)ans++;//如果用的时间超过所需的时间说明解决了
        cout<<ans<<endl;
    }
    return 0;
}

B. Preparing for the Contest

#include<iostream>
using namespace std;
int main()
{
    int t;cin>>t;
    while(t--)
    {
       int n,k;cin>>n>>k;
       for(int i=1;i<=k;i++)
       cout<<i<<' ';//前面单增先让它兴奋k次
       for(int i=0;i<n-k;i++)
       cout<<n-i<<' ';//后面单减就不兴奋了
       cout<<endl;
    }
    return 0;
}

D - Three Activities

第一眼看有点像分组背包,但后面发现比分组背包多了一个限制条件,所以没什么软用,还是得用状态压缩dp,f[i][j]表示第i天时,状态是j时的最大值,j用000到111的二进制数依次表示一个也没选到三个都选了,也就是0-7,状态转移方程f[i][j]=max(f[i-1][j],f[i-1][j-(1<<k)]+a[k][i]),k表示的是选哪一件事,因为一天只能选一件事,所以分别枚举,每个状态j,从三个里面取最大值,举个具体一点的例子,比如第i天选第2件事,且每件事都已经选了那么方程就是

f[i][111]=max(f[i-1][111],f[i-1][101]+a[2][i])  上代码

#include<iostream>
#include<cstring>
using namespace std;
const int N=100010;
int f[8],a[3][N];
//由于是滚动数组,可以优化成一维,然后计算状态的时候从大到小枚举覆盖即可,这里详细说一些为什么可以覆盖,因为计算某一个状态一点是根据一个比他小的状态来算的,从大到小枚举可以保证算大的状态的时候小的状态还在上一层没有被更新过
int n;
int main()
{
    int t;cin>>t;
    while(t--)
    {
        memset(f,0,sizeof f);
        cin>>n;
        for(int i=0;i<3;i++)
           for(int j=1;j<=n;j++)cin>>a[i][j];
        for(int i=1;i<=n;i++)//枚举每一天
        for(int j=7;j>0;j--)//枚举每一个状态
        for(int k=0;k<3;k++)//枚举选哪一件事
        if((j>>k)&1)f[j]=max(f[j],f[j-(1<<k)]+a[k][i]);
        cout<<f[7]<<endl;
        
    }
    return 0;
}

C - Quests

把他解锁1,2,3......min(k,n)的任务时获得的最大值都算出来,然后比较取最大值,如果他不打算解锁任务了那么他剩下的次数一定全部都要用来完成已解锁任务中最大的那个才可以保证最终结果最大

#include<iostream>
using namespace std;
int n,k,a[200010],b[200010],f[200010];
int main()
{
    int t;cin>>t;
    while(t--)
    {
       cin>>n>>k;
       for(int i=1;i<=n;i++)cin>>a[i];
       for(int i=1;i<=n;i++)cin>>b[i];
       for(int i=1;i<=n;i++)a[i]+=a[i-1];//先算出前缀和后面计算的时候会方便很多
       int ma=0;//ma用来存储已完成任务中的最大值,方便以后一直完成ta
       int ans=0;
       for(int i=1;i<=n&&i<=k;i++)
       {
           if(b[i]>ma)ma=b[i];
           f[i]=a[i]+(k-i)*ma;
           ans=max(ans,f[i]);
       }
       cout<<ans<<endl;
    }
    return 0;
}

E1&E2Game with Marbles

贪心,选择一种颜色的弹珠意味着将对方这种颜色的弹珠清空,并且保住了自己的弹珠,换个角度思考,其实就等价与,初始都没有弹珠,然后选了某种颜色的弹珠就将这种颜色的弹珠全部拿走,然后每个人都会选择当前最多的那堆弹珠,于是按每种颜色弹珠之和排个序就行了,这里可以定义一个结构体来存

#include<iostream>
#include<algorithm>
using namespace std;
struct NUM
{
    int a,b,c;
    bool operator< (const NUM &W)const
    {
        return c < W.c;//c表示他们的和,按照c的大小排序
    }
}x[200010];
int main()
{
    int t;cin>>t;
    while(t--)
    {
        int n;cin>>n;
        long long cnt1=0,cnt2=0;//用来统计两人目前的弹珠数量
        for(int i=1;i<=n;i++){cin>>x[i].a;cnt1+=x[i].a;}
        for(int i=1;i<=n;i++){cin>>x[i].b;cnt2+=x[i].b;}
        for(int i=1;i<=n;i++)x[i].c=x[i].b+x[i].a;
        sort(x+1,x+n+1);
        reverse(x+1,x+n+1);将结构体从大到小排好序选择即可
        for(int i=1;i<=n;i++)
        {
            if(i%2==1)一人选一次
            {
                cnt1--;
                cnt2=cnt2-x[i].b;
            }
            else {
                cnt2--;
                cnt1=cnt1-x[i].a;
            }
        }
        cout<<cnt1-cnt2<<endl;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值