B - Array Walk (Round 92 div2 贪心 枚举)

B - Array Walk

题意: 给定一个长度为 n 的数组,从位置1开始可以向右累加 k 次,且可以向左累加 z 次,但不能连续两次及以上向左累加,求最大累加和。
思路: 贪心的考虑,在往右累加的过程中,若需要循环节的存在,则一定只要最大的一个循环节,所以我们在枚举最终停止位置时,同时记录最大的循环节,然后计算停止在每个位置能得到的最大累加和,再取最大即可。

Code1:

#include
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long LL;
const int N = 3e5+7;
LL a[N];

int main()
{
	IO;
	int T; cin>>T;
	while(T--){
		int n,k,z;
		cin>>n>>k>>z;
		for(int i=1;i<=n;i++) cin>>a[i];
		LL ans=0,mx=0,sum=0;
		k+=1;
		for(int i=1;i<=k;i++){
			sum += a[i];
			if(i<n) mx = max(mx,a[i]+a[i+1]);  //寻找最大循环节 
			ans = max(ans,min((k-i)/2,z)*mx+sum); //枚举右边的最终位置 
		}
		cout<<ans<<"\n";
	}
	return 0;
}

思路: DP暴力求解, d p [ i ] [ j ] dp[i][j] dp[i][j] 表示第 i 位向左累加了 j 次能获得的最大累加值。

Code2:

#include
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long LL;
const int N = 1e5+7;
LL a[N];
LL dp[N][6];

int main()
{
	IO;
	int T; cin>>T;
	while(T--){
		int n,k,z;
		cin>>n>>k>>z;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			dp[i][0] = dp[i-1][0]+a[i];   //初始化边界
			for(int j=1;j<=z;j++) dp[i][j]=0; 
		}
		LL ans = dp[k+1][0];
		for(int j=1;j<=z;j++){
			for(int i=1;i<=n;i++){
				if(j*2+i<=k+1){	  //满足转移条件
					dp[i][j] = max(dp[i][j],dp[i-1][j]+a[i]);  //从i-1转移来
					dp[i][j] = max(dp[i][j],dp[i+1][j-1]+a[i]); //从j-1转移来
				}
				ans = max(ans,dp[i][j]);
			}
		}
		cout<<ans<<"\n";
	}
	return 0;
}

你可能感兴趣的:(DP,贪心,CF)