丁丁最近沉迷於乙個數字遊戲之中。這個遊戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個遊戲並不那麼容易。遊戲是這樣的,在你面前有一圈整數(一共\(n\)個),你要按順序將其分為\(m\)個部分,各部分內的數字相加,相加所得的\(m\)個結果對\(10\)取模後再相乘,最終得到乙個數\(k\)。遊戲的要求是使你所得的\(k\)最大或者最小。
例如,對於下面這圈數字(\(n=4,m=2\)):
要求最小值時,\(((2−1) mod 10)×((4+3) mod 10)=1×7=7\),要求最大值時,為\(((2+4+3) mod 10)×(−1 mod 10)=9×9=81\)。特別值得注意的是,無論是負數還是正數,對\(10\)取模的結果均為非負值。
丁丁請你編寫程式幫他贏得這個遊戲。
輸入檔案第一行有兩個整數,\(n(1≤n≤50)\)和\(m(1≤m≤9)\)。以下\(n\)行每行有個整數,其絕對值\(≤10^4\),按順序給出圈中的數字,首尾相接。
輸出檔案有\(2\)行,各包含\(1\)個非負整數。第\(1\)行是你程式得到的最小值,第\(2\)行是最大值。
4 243-12
7對於這種資料,我這種蒟蒻都能看出來,相信很多dalao看到都能一眼就看出來要把環換成鏈,這是第乙個思想。81
然後第二個思想就是取模的問題,由於負數取模應為正,假設這個數為\(n\),我們就可以寫乙個函式來進行取模運算,也就是\((n\%10+10)\%10\),為什麼要這麼處理呢,這樣就可以把負數取完模變為正,而對於正數就毫無影響,這是乙個比較巧妙也重要的處理。
第三個就是字首和,因為要求和,所以利用字首和就可以很大的提高效率,思想也會比較明了。
根據dp思想,我們就可以進行狀態轉移。開乙個\(dp\)陣列,\(dp[i][j][len]\)代表從\(i\)到\(j\)分成\(len\)段的大小,依次列舉段數,左右端點,和斷點,每一次從\(i\)到\(j\)都是由上乙個從\(i\)到斷點\(c\)分成\(len-1\)段的狀態轉移而來,轉移的過程就是乘上從\(j\)到\(c\)的字首和取模。我們令取模的函式為\(mod\),那麼狀態轉移方程如下:(最大值和最小值一樣,唯一要注意的是,最大值初始為\(0\),最小值每一次轉移要改為\(0x3f3f3f3f\))
\[f1[l][r][len] = min(f1[l][r][len],f1[l][k][len-1]*mod(sum[r]-sum[k]));\\
f2[l][r][len] = max(f2[l][r][len],f2[l][k][len-1]*mod(sum[r]-sum[k]));\]
最終再從頭到尾掃一遍得結果。
#includeusing namespace std;
int mod(int x)
int n,m;
const int maxn = 105;
int sum[maxn],a[maxn];
int f1[maxn][maxn][10],f2[maxn][maxn][10];
int main()
for(int i=1;i<=2*n;++i)
for(int i=1;i<=2*n;++i)
} for(int len=2;len<=m;++len)
}} }
int max = f2[1][n][m];
int min = f1[1][n][m];
for(int i=1;i<=n;++i)
cout<
//vocanda
}
線性dp 區間dp
1 尼克的任務 額一道挺水的題,愣是做了幾個小時 動態規劃大致的思路還是找乙個轉移 換個詞就是影響 我們可以明顯看出本題的規則 空暇時,一遇到任務必須挑乙個接 求1 n時間內最大空暇時間 所以將任務排序是必要的,兩個關鍵字 再來想象一下當我做到第i 個任務時,我在 st i st i t i 1 時...
luogu 1043 數字遊戲(區間dp)
題目描述 丁丁最近沉迷於乙個數字遊戲之中。這個遊戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個遊戲並不那麼容易。遊戲是這樣的,在你面前有一圈整數 一共n個 你要按順序將其分為m個部分,各部分內的數字相加,相加所得的m個結果對10取模後再相乘,最終得到乙個數k。遊戲的要求是使...
P1043 數字遊戲(區間dp )
思路 因為要求分為k個區間,所以依次列舉將區間分為k個,然後列舉左右區間,求出區間的最大,最小值。注意 陣列開兩倍。include using namespace std typedef long long ll const int n 105 ll dp 2 n n n a n const ll ...