题意: 请用n个字符组成一个字符串使得到的权值最大,其中仅有"td","qcjjkkt","qcjjkktd"这三个字符串有权值,每包含这样一个字符串的权值是b,a,a+b。
知识点: 贪心,动态规划
思路: 因为这题的数据范围很大,直接dp会超时,然后我们可以发现这三个字符串长度为2,7,8,他们的最大公约数是56,所以我们可以做到贪心出每56个字符所贡献的最大值是多少,也就是max(8a,28b,7(a+b)),但是如果直接把前56x个字符全部枚举完之后再去动态规划剩下的字符串就会出问题,比方说
tdtdtdtd
这是正好56个结束
假如后面还剩下3个位置
其中会出现把前面两个td删掉
换成tdtdqcjjkkt更优的情况出现
所以我们需要留一个缓冲区,也就是n%56+56,多给56个来dp就可以得到最优结果了。
其中动态规划也很好想,因为dp[i]只有4种情况,一种是他前边全是td,然后这一格什么都不用加就是最大,也就是dp[i-1],一种他前边一格是个空的,所以你可以加个td成为最大,也就是dp[i=2]+b,接下来几种同理,dp[i-7]+a,dp[i-8]+a+b,这四种情况取最大即可。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define PLL pair<ll,ll>
#define PII pair<int,int>
#define endl '\n'
using namespace std;
const int m=1000000007;
int main()
{
cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
int t;
cin >> t;
while(t--){
ll n,a,b;
cin >> n >> a >> b;
ll maxn=(max(8*a,max(28*b,7*(a+b)))),x=0;
if(maxn==8*a)
x=(n/56-1)*8LL*a;
else if(maxn==28*b)
x=(n/56-1)*28LL*b;
else
x=(n/56-1)*7LL*(a+b);
if(n>=56)
n=n%56+56;
vector<ll> dp(n+1);
dp[0]=max(x,0LL);
for(int i=1;i<=n;i++)
{
dp[i]=max(dp[i-1],dp[i]);
if(i-2>=0)
dp[i]=max(dp[i-2]+b,dp[i]);
if(i-7>=0)
dp[i]=max(dp[i-7]+a,dp[i]);
if(i-8>=0)
dp[i]=max(dp[i-8]+a+b,dp[i]);
}
cout << dp[n] << endl;
}
return 0;
}

京公网安备 11010502036488号