牛客小白月赛58 B(暴力)C(思维)D(dp滚动数组优化)

牛客小白月赛58

感觉没什么意思,这场月赛出题人有点问题。

B
题意:给定一定的数据填充顺序和每一个填充层的名称,只有填充满了上一层才可以填充下一层。
但是每一层又属于某一个大层,一个大层中包含了若干不同的小层。输出时请按照先大层后小层的顺序来输出,小层请按照小层的顺序来输出。

大层顺序:按照数字1 2 3 4 5 6 7

小层顺序:按照字母spdf顺序来输出

思路:暴力,先把填充顺序打个表,然后再把输出顺序打个表,然后用map存一下每一层的填充数,然后按照输出顺序去遍历即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int con[20]={0,2,2,6,2,6,2,10,6,2,10,6,2,14,10,6,2,14,10,6};
string pos[20]={"0","1s","2s","2p","3s","3p","4s","3d","4p","5s","4d","5p","6s","4f","5d","6p","7s","5f","6d","7p"};
string ans[20]={"0","1s","2s","2p","3s","3p","3d","4s","4p","4d","4f","5s","5p","5d","5f","6s","6p","6d","7s","7p"};
map<string,int>mp;
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    for(cin>>t;t;t--)
    {
        mp.clear();
        int n;
        cin>>n;
        int cnt=1;
        while(n)
        {
            if(n>con[cnt])
            {
                n-=con[cnt];
                mp[pos[cnt]]=con[cnt];
                cnt++;
            }
            else if(n<=con[cnt])
            {
                mp[pos[cnt]]=n;
                cnt++;
                n=0;
            }
        }
        for(int i=1;i<20;i++)
            if(mp[ans[i]])
                cout<<ans[i]<<mp[ans[i]]<<" ";
        cout<<endl;
    }
    return 0;
}

C:
题意:有n个数,每个数的范围是【1,m】,要求尽量从中选出n-2个数使其总和可以被m整除,如果这n-2个数的总和为sum,剩下两个数的总和为res

定义这n个数的价值如下

1.如果sum无法被m整除,那么其价值为0

2.如果sum可以被m整除,并且res也可以被m整除,价值为m

3.如果sum可以被整除,但res不能,那么价值为res%m

题目保证价值的唯一性。

思路:经典的举一推一做法。
我们遍历整个数组,假设当前的数就是我们要找的剩下的两张牌中的一张,那么为了让sum可以被m整除另一张势必是剩下的n-1张牌的总和取模于m的余数。如果不存在这样的两张牌,说明无法找出一个sum让其取模于m为0。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+100;
int a[N];
map<int,int>mp;
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t;
    for(cin>>t;t;t--)
    {
        mp.clear();
        int n,m,sum=0;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            sum+=a[i];
            mp[a[i]]++;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int temp=sum-a[i];//枚举抽走一张牌
            mp[a[i]]--;//防止重复抽一张牌
            int res=temp%m;//剩下的牌,想要再收走一张然后满足取模m等于0,就需要抽走temp%m的价值
            if(res==0)//说明得抽走一张价值为m的牌
                res=m;
            if(mp[res])//如果存在这样的牌
            {
                res+=a[i];//两张牌的和
                if(res%m==0)
                    ans=m;
                else
                    ans=res%m;
                break;
            }
            mp[a[i]]++;//放回去
        }
        cout<<ans<<'\n';
    }
    return 0;
}

D
题意:
给定n个题目,有难度系数a和分数b,P值,W值
某人有初始压力值p,并且没做完一个题就可以让压力在[0,k]的范围内减小P或者增加W

如果当前压力值p小于b那么就可以做出这个题,并且获得点数a*p
如果当前压力值大于b那么就无法获得点数。

求,如果初始压力值你可以在[0,k]中随便选,n个题目你能获得的最大点数是多少。

特别的,此题空间限制位64MB

思路

设dp[i][j]为前i个物品在压力值为k的情况下的最大获得点数

然后发现第i个物品的答案只和i-1个物品的答案相关,所以只需要第一维的空间为2即可。

状态为dp[now][j]=max(dp[bef][j]+val[now],dp[bef][j-q[i-1]]+val[now],dp[bef][j+w[i-1]]+val[now]);

具体实现见代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+100;
int n,m,k;
int a[N],b[N],q[N],w[N];
inline int gval(int x,int i){
    return x>b[i]?0:x*a[i];
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i]>>b[i]>>q[i]>>w[i];
    vector<int> dp(k+1,0);
    for(int i=1;i<=n;i++)
    {
        vector<int> bef=dp;
        for(int j=0;j<=k;j++) 
        {
            if(i>1)
            {
                dp[j]=max(dp[j],bef[j]+gval(j,i));
                if(j-q[i-1]>=0)
                    dp[j]=max(dp[j],bef[j-q[i-1]]+gval(j,i));
                if(j+w[i-1]<=k)
                    dp[j]=max(dp[j],bef[j+w[i-1]]+gval(j,i));
            }
            else
                dp[j]=gval(j,i);
        }
    }
    int ans=0;
    for(int i=0;i<=k;i++)
        ans=max(ans,dp[i]);
    cout<<ans<<'\n';
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值