[Wannafly] 挑战赛12

[传送门](https://www.nowcoder.com/acm/contest/79#question)
A-银行存款
------
DP or 搜索

DP解法
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
double dp[maxn];
double f[6];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        scanf("%lf%lf%lf%lf",&f[1],&f[2],&f[3],&f[5]);
        double f1 = (1+f[1]),f2=(1+f[2])*(1+f[2]);
        double f3 = (1+f[3])*(1+f[3])*(1+f[3]);
        double f5 = (1+f[5])*(1+f[5])*(1+f[5])*(1+f[5])*(1+f[5]);
        memset(dp,0,sizeof(dp));
        dp[n] = 1.0;
        for(int i=n;i>=0;i--) {
            if(i-5 >= 0) dp[i-5] = max(dp[i-5],dp[i]*f5);
            if(i-3 >= 0) dp[i-3] = max(dp[i-3],dp[i]*f3);
            if(i-2 >= 0) dp[i-2] = max(dp[i-2],dp[i]*f2);
            if(i-1 >= 0) dp[i-1] = max(dp[i-1],dp[i]*f1);
        }
        printf("%.5f\n",dp[0]);
    }
    return 0;
}


DFS解法


#include<bits/stdc++.h>
using namespace std;
double ans,f1,f2,f3,f5;
void dfs(int now,double val)
{
    if(now == 0) {
        ans = max(ans,val);
        return;
    }
    if(now >= 5) {
        dfs(now-5,val*(1.0+f5)*(1.0+f5)*(1.0+f5)*(1.0+f5)*(1.0+f5));
    }
    if(now >= 3) {
        dfs(now-3,val*(1.0+f3)*(1.0+f3)*(1.0+f3));
    }
    if(now >= 2) {
        dfs(now-2,val*(1.0+f2)*(1.0+f2));
    }
    if(now >= 1) {
        dfs(now-1,val*(1.0+f1));
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        scanf("%lf%lf%lf%lf",&f1,&f2,&f3,&f5);
        ans = 0.0;
        dfs(n,1.0);
        printf("%.5f\n",ans);
    }
    return 0;
}


B-T95要减肥--------前缀和

麦当劳肯定从快乐值高的开始吃,赛道肯定从痛苦值低的开始跑。
因为吃麦当劳得到的快乐值非负,所以有吃麦当劳的次数=跑步的次数。
那么我们只要枚举吃了几次麦当劳(即跑了几次步)就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
ll a[maxn],b[maxn],dp[maxn];
int main()
{
    int n;
    ll m;
    while(~scanf("%d%lld",&n,&m))
    {
        for(int i=0;i<n;i++) scanf("%lld",&a[i]);
        for(int i=0;i<n;i++) scanf("%lld",&b[i]);
        sort(a,a+n);sort(b,b+n);
        ll ans = 0,temp = 0;
        for(int i=0;i<n;i++) {
            if(i%3==2) {
                temp = temp-a[i]+b[n-i-1]+m;
                ans = max(ans,temp);

            }
            else {
                temp = temp - a[i] + b[n-i-1];
                ans = max(ans,temp);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

C-删除子串------DP :表示不是很理解,赛后看了q神的代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
char str[maxn];
int dp[maxn][12][2]; ///dp[i][j][k] 表示后n-i个字符j个变化时其字母为k时最大的长度
int main()
{
    int n,m;
    scanf("%d%d%s",&n,&m,str);
    for(int i=n-1;i>=0;i--)
        for(int j=0;j<=m;j++)
            for(int k=0;k<2;k++)
            {
                dp[i][j][k] = max(dp[i][j][k],dp[i+1][j][k]);
                int tk=str[i]-'a',tj=j+(k!=tk);
                if(tj<=m) dp[i][tj][tk] = max(dp[i][tj][tk],dp[i+1][j][k]+1);
            }
    int res = 0;
    for(int i=0;i<=m;i++) {
        res = max(res,dp[0][i][0]);
    }
    cout<<res<<endl;
    return 0;
}

以下是用二维进行理解

f[i][j]表示前 i 个字符,变化了 j 次后保留的字符串长度的最大值。
当 j 确定的时候,保留字符串的最后一位是 a 是 b 也是确定的。
当保留的字符串的最后一位与当前位一样时,直接保留这一位;
否则,当保留的字符串的最后一位与当前位不一样时,有两种选择,要不删除这一
位,要不变化一次。转移一下即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
char str[maxn];
/**
    dp[i][j] :
    表示说前i个字符变化了j次后保存的字符串最大长度于是答案就是
    max(dp[n][j],0<=j<=m)
*/
int dp[maxn][15];
int main()
{
    int n,m;
    while(~scanf("%d%d%s",&n,&m,str)) {
	bool flag = false;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++) {
            for(int j=0;j<=m;j++) {
                ///dp[i][j] 应当继承上一个的最大值
                dp[i][j] = max(dp[i-1][j],dp[i][j]);
                ///如果当前字符和变化j字符相等,直接加上。
                if(str[i-1] == (j&1)+'a') dp[i][j] = max(dp[i][j],dp[i-1][j] + 1);
                ///不相等的时候,第一种删除长度不变,变化不变,i+1:dp[i][j]已经继承了dp[i-1][j]的大小,所以dp[i][j]不变
                ///第二种:让变化数+1,保留当前字符。于是长度加1,变化加1,i+1,
                ///转移的是dp[i][j+1]状态;dp[i][j+1] = max(dp[i][j+1],dp[i-1][j]+1)
                else dp[i][j+1] = max(dp[i][j+1],dp[i-1][j]+1);
            }
            if(str[i] == 'a') flag = true; ///排除全b情况
        }
        int ans = 0;
        for(int i=0;i<=m;i++) ans = max(ans,dp[n][i]);
        if(flag) printf("%d\n",ans);
        else printf("0\n");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值