[传送门](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;
}
以下是用二维进行理解
当 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;
}