給乙個由 n
nn 個數組成的環,講環拆成 m
mm 份,每份求和最後相乘,求最大/最小值。
一道區間 dpdp
dp題,首先因為是環,常規做法就是拆環,用兩倍數組裝,又要對每份求和,那就需要用到字首和。
陣列 dp[
i][j
]dp[i][j]
dp[i][
j]表示將 j
jj 個數分成 i
ii 份的最大/最小值
區間 dpdp
dp常規做法列舉分割點 k
kk, 那麼狀態轉移方程 dp[
i][j
]=ma
x/mi
n(dp
[i][
j],d
p[i−
1][k
]∗su
m[k+
1,j]
)dp[i][j] = max/min(dp[i][j], dp[i-1][k] * sum[k+1, j])
dp[i][
j]=m
ax/m
in(d
p[i]
[j],
dp[i
−1][
k]∗s
um[k
+1,j
])因為是環,所以每個點都可以當作起點 dpdp
dp, 所以我的做法就是每次傳遞乙個偏移量x,因為根據狀態轉移方程,並不會用到原陣列,只會用到對應區間的和。
初始化要特別注意,因為分成 1
11 份的時候,並不好處理,所以提前預處裡更方便
具體看**
#include
using
namespace std;
#define me(a, b) memset(a, b, sizeof(a))
#define ios() ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
typedef
long
long ll;
typedef pair pll;
typedef pair<
int,
int> pii;
const
int inf =
0x3f3f3f3f
;const
int maxn =
1e2+5;
const ll mod =10;
ll d1[maxn]
[maxn]
;ll d2[maxn]
[maxn]
;ll a[maxn<<1]
;ll pre[maxn<<1]
;ll getsum
(int l,
int r)
pll solve
(const
int& n,
const
int& m,
const
int& x)
for(
int i =
1; i <= n;
++i)
d1[1]
[i]= d2[1]
[i]=
getsum(1
+x, i+x)
;for
(int i =
2; i <= m;
++i)}}
return
make_pair
(d1[m]
[n], d2[m]
[n]);}
intmain()
for(
int i =
1; i <=
2*n;
++i)
pll ans
(inf,0)
;for
(int i =
0; i < n;
++i)
cout << ans.first << endl << ans.second << endl;
return0;
}
這題做了一兩個小時,就是因為邊界和初始化想暈了,最後重新構思就一遍過了。 P1043 數字遊戲
丁丁最近沉迷於乙個數字遊戲之中。這個遊戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個遊戲並不那麼容易。遊戲是這樣的,在你面前有一圈整數 一共n個 你要按順序將其分為m個部分,各部分內的數字相加,相加所得的m個結果對10取模後再相乘,最終得到乙個數k。遊戲的要求是使你所得的k...
P1043 數字遊戲
丁丁最近沉迷於乙個數字遊戲之中。這個遊戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個遊戲並不那麼容易。遊戲是這樣的,在你面前有一圈整數 一共n個 你要按順序將其分為m個部分,各部分內的數字相加,相加所得的m個結果對10取模後再相乘,最終得到乙個數k。遊戲的要求是使你所得的k...
P1043 數字遊戲
研究環狀dp 可以開雙倍大小的陣列用以表示環 表示為 f i j l 從i 到 l 的區間裡,劃分 l 段 進行遞推前,需要初始化 f i j 1 然後有乙個小細節就是sum 進行字首和優化 將 o n 的東西優化成 o 1 可以加快節奏 讀取最值時記得掃一遍環 f i i n 1 i 1 n 狀態...