Make The Fence Great Again CodeForces - 1221D(dp|类比01背包)

在这里插入图片描述在这里插入图片描述
题意:题目要求对n个数中的某些进行任意多次的+1操作,使得对于每个元素(除开第一个)有a[i-1]!=a[i],1<i<=n,由于每个a[i]对应一个b[i],没增加1,那么费用就相应增加1*b[i],问使得在修改为满足条件a[i-1]!=a[i]的情况下最小的费用;
这个题我也是看了题解才明白的,由于每次增加1,所以最多一个元素可以增加2次1就能保证左相邻是不想等的了;
比如一个序列:1,1,1;那么我增加第二个1一次即可,如果是2,1,1,3,3;那么增加第一个1两次才行,所以这点就很重要了,一个元素只能增加0/1/2次;所以我需要把所有的情况全部枚举出来,这我感觉就是dp的思路了,就像01背包一样的感觉;01背包是对于这个物品我想么选,要么不选,所以需要枚举所有情况;而这道题是当前元素增加0次,1次或者2次,都是多种情况;注意题目中1e18,所以我需要设置无穷大为1e18多一点;对于dp那么我就需要枚举三种情况;具体一点就是:对于第一个篱笆,他有0,1,2三种情况,那么对应的第二个篱笆也是0,1,2三种情况,所以我需要两个for来枚举,由于一共有n的篱笆,所以我外面还需要一个for,并且在a[i-1]+j!=a[i]+k的情况下才能计算;
所以dp定义为dp[i][k]当修到第i个篱笆的时候增加k次的最小费用;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll q,n;
ll dp[300050][3];
ll a[300050],b[300050];
const ll INF=1e18+500;
int main(){
    
    
	scanf("%lld",&q);
	while(q--){
    
    
		scanf("%lld",&n);
		  for(int i=1;i<=n;i++){
    
    
		  	  scanf("%lld %lld",a+i,b+i);
		  	  dp[i][0]=dp[i][1]=dp[i][2]=INF;
		  }
		  dp[1][0]=0;dp[1][1]=b[1];dp[1][2]=2*b[1];//初始化修到第一个fence时候的三种情况
		  for(int i=2;i<=n;i++){
    
    
		  	   for(int j=0;j<=2;j++){
    
    
		  	   	     for(int k=0;k<=2;k++){
    
    
		  	   	     	      if(a[i-1]+j==a[i]+k)continue;//当不相等的时候才计算修改费用 
		  	   	     	      dp[i][k]=min(dp[i][k],dp[i-1][j]+k*b[i]);//第i个篱笆增加k次与第i-1篱笆增加j次的费用的和的最大值 
						  }
				 }
		  } 
		  ll ans=min(dp[n][0],min(dp[n][1],dp[n][2]));//这里计算的就是前面总的 
		  printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44555205/article/details/104339913
今日推荐