做題小結 DP訓練

LteShuai發表於2024-08-09

第一個

開了個二維陣列表示刪除不刪除
然後去重了下 如果前後相差為1的話 ,就可以進行刪除的思考 此時i要刪除
的話 i-1必須要不刪除 如果i不刪除的話 存一個前面的max即可
這邊注意下可能有重複的數

如果前後相差不為1的話 我們就可以肆無忌憚 怎麼搞都行

此題結束

第二題

這題和上一題相對比起來更難了

int dp[range][4][10];	
dp[1][0][0] = 0; 不動
dp[1][1][1] = 1; //左
dp[1][1][2] = 0; //右邊

我這邊預設左可刪的 如果在距離夠的情況下 但是右邊可以不可以刪除取決於後面的距離夠不夠

	dp[i][0][0] = max(max(dp[i - 1][0][0], dp[i][0][0]), max(dp[i - 1][1][1], dp[i - 1][1][2]));
		if (x[i] - x[i - 1] > h[i] && x[i] - x[i - 1] <= h[i] + h[i - 1]) {
			dp[i][1][1] = max(max(dp[i - 1][0][0] + 1, dp[i][1][1]), max(dp[i - 1][1][2], dp[i - 1][1][1] + 1));
		} else if (x[i] - x[i - 1] > h[i] + h[i - 1]) {
			dp[i][1][1] = max(max(dp[i - 1][0][0] + 1, dp[i][1][1]), max(dp[i - 1][1][2] + 1, dp[i - 1][1][1] + 1));
		}
		if (x[i + 1] - x[i] > h[i]) {
			dp[i][1][2] = max(max(dp[i][1][2], dp[i - 1][0][0] + 1), max(dp[i - 1][1][2] + 1, dp[i - 1][1][1] + 1));
		}

完整程式碼 邏輯很清晰

第三

這題沒做出來
我們要思考到 我們只有一次的操作機會
所以我們只能對那種中間夾了個沒用的數進行刪除
本來是上升的 由於這個數改變了
思考到這個就簡單了 我們求一個字尾 二者拼在一塊就是答案

第四個題

非常好的一個題
沒做出來 這題蠻有意思的 真沒想到
因為我沒想到這個狀態轉移方程
fi=max(fi-1,fj-1+i-j+1)
如果暴力做 是個n方的寫法
考慮最佳化 可以發現fj-1-j+1可以弄成一個東西
於是使用map代替下

	for(int i=0;i<=n;i++)
	{	dp[i]=0;cnt[i]=-1e9;}
	//這題我不會
	//dp[i]=dp[i-1],dp[j-1]+i-j+1
	//做dp要先從n^2的情況下推轉移方程 然後去最佳化
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)
	{
	dp[i]=max(dp[i-1],i+cnt[a[i]]+1);
	cnt[a[i]]=max(cnt[a[i]],dp[i-1]-i);	
	}
	cout<<dp[n]<<endl;

下一個機率dp

很有意思的一道機率dp

我就講正解思路了

給出這麼多組操作 真正有用的其實就是第一個我們要一次到位的那個數

舉個例子 4 2 1 3 5 就是那個4 能直接操作4的那個才有用
於是我們可以知道這個轉移方程式就是ans=ans+(1-ans)*p
初始ans=0 我們假設第一次操作成功=p 後面就是說第一次不成功。。第二次也不成功。。。。。

很好一個題

這個題我的思路就是對於a分類
有兩種a一個是做第一個位置的a 另一個是最後位置的
然後求一個字尾和對於第二類的a然後再for迴圈碰到a的話

dp[i][1] = dp[i - 1][1] + 1;
dp[i][2] = dp[i - 1][2];
dp[i][3] = max(dp[i-1][2] + asum[i],dp[i][3]);

這是b
		dp[i][1] = dp[i - 1][1];
			dp[i][2]=max(dp[i-1][1],dp[i-1][2])+1;
			dp[i][3]=max(dp[i][2]+asum[i],dp[i][3]);

就這樣了 就ac了 想的話 還好

這是一個橙題 不過我覺得挺有意思的 很體現dp思想
對於一個正方形 我們就必須想到 一個點作為正方形的右下

那就必須滿足他的左邊 上面 對角 都要有值 而且這個值大家都要用 否則
無法構成正方形的 於是 狀態轉移就出來了 取一個min就可以了

相關文章