1. 程式人生 > >Vijos P1218 數字遊戲

Vijos P1218 數字遊戲

ram 個數字 for blog tex div too numbers else

描述

丁丁最近沈迷於一個數字遊戲之中。這個遊戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個遊戲並不那麽容易。遊戲是這樣的,在你面前有一圈整數(一共n個),你要按順序將其分為m個部分,各部分內的數字相加,相加所得的m個結果對10取模後再相乘,最終得到一個數k。遊戲的要求是使你所得的k最大或者最小。

格式

輸入格式

輸入文件第一行有兩個整數,n(1≤n≤50)和m(1≤m≤9)。以下n行每行有個整數,其絕對值不大於10^410?4??,按順序給出圈中的數字,首尾相接。

輸出格式

輸出文件有兩行,各包含一個非負整數。第一行是你程序得到的最小值,第二行是最大值。

樣例1

樣例輸入1

4 2
4
3
-1
2

樣例輸出1

7
81

限制

各個測試點1s

提示

DP!^_^

【分析】

典型的區間dp,明明是普及組第二題還調了半天...果然還是熟練度的問題。

【代碼】

 1 #include <bits/stdc++.h>
 2 #define fo(i, j, k) for(int i=j;i<=k;++i)
 3 using namespace std;
 4 
 5 long long ans, n, m, a[51], b[51], dp[10][105][105];
 6 
 7 void init() {
 8     cin >> n >> m;
9 for (int i=1;i<=n;++i){ 10 cin >> a[i]; 11 b[i]=b[i-1]+a[i]; 12 } 13 fo(i, n+1, 2*n-1) 14 b[i]=b[i-1]+a[i-n]; 15 } 16 17 void DP1() 18 { 19 ans=0x7fffffff; 20 for (int i=0;i<=m;++i) 21 for (int j=0;j<=2*n;++j) 22 for (int k=0
;k<=2*n;++k) 23 dp[i][j][k]=0x7fffffff; 24 for (int k=1;k<=m;++k) 25 for (int i=1;i<2*n;++i) 26 for (int t=1;t<=n;++t) { 27 int j=i+t-1; 28 if (j>2*n-1) 29 break; 30 if (k==1){ 31 dp[k][i][j]=((b[j]-b[i-1])%10+10)%10; 32 } 33 else { 34 for (int q=i;q<j;++q){ 35 dp[k][i][j]=min(dp[k][i][j], dp[1][i][q]*dp[k-1][q+1][j]); 36 } 37 } 38 } 39 for (int i=1;i<=n;++i){ 40 ans=min(ans, dp[m][i][i+n-1]); 41 } 42 cout << ans << endl; 43 } 44 45 void DP2() 46 { 47 ans=-0x7fffffff; 48 for (int i=0;i<=m;++i) 49 for (int j=0;j<=2*n;++j) 50 for (int k=0;k<=2*n;++k) 51 dp[i][j][k]=-0x7fffffff; 52 for (int k=1;k<=m;++k) 53 for (int i=1;i<=n;++i) 54 for (int t=1;t<=n;++t) { 55 int j=i+t-1; 56 if (j>2*n-1) 57 break; 58 if (k==1) 59 dp[k][i][j]=((b[j]-b[i-1])%10+10)%10; 60 else { 61 for (int q=i;q<j;++q) { 62 dp[k][i][j]=max(dp[k][i][j], dp[1][i][q]*dp[k-1][q+1][j]); 63 } 64 } 65 } 66 for (int i=1;i<=n;++i) 67 ans=max(ans, dp[m][i][i+n-1]); 68 cout << ans << endl; 69 } 70 71 int main() 72 { 73 init(); 74 DP1(); 75 DP2(); 76 }

Vijos P1218 數字遊戲