數字遊戲 (vijos 1218)
阿新 • • 發佈:2019-02-15
Description
【問題描述】
丁丁最近沉迷於一個數字遊戲之中。這個遊戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個遊戲並不那麼容易。遊戲是這樣的,在你面前有一圈整數(一共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取模的結果均為非負值。 丁丁請你編寫程式幫他贏得這個遊戲。
Input
輸入有多組資料,對於每一組資料:第一行有兩個整數,n(1<=n<=50)和m(1<=m<=9)。以下n行每行有個整數,其絕對值不大於104,按順序給出圈中的數字,首尾相接。
Output
對於每組資料,輸出有兩行,各包含一個非負整數。第一行是你程式得到的最小值,第二行是最大值。
Sample Input
4 2 4 3 -1 2 4 2 4 3 -1 2
Sample Output
7 81 7 81
Source NOIP2003普及組
狀態:
把環拆成鏈,列舉開始位置
d[i][j]表示前i個數分成j部分的最優值
狀態轉移方程:
d[i][j]=opt(d[i][j],d[k][j-1]*(((s[i]-s[k])%10+10)%10))
s[i]是前i個數的和
邊界:
d[0][0]=1;
d[i][1]=((s[i]%10+10)%10)
程式碼:
- #include<cstdio>
- #include<algorithm>
- usingnamespace std;
- int n,m,Max,Min,s[55],d[55][10],dp[55][10];
- void DP(int a[])
- {
- int i,j,k;
-
for(i=1;i<=n;i++)
- s[i]=s[i-1]+a[i];
- for(i=0;i<=n;i++)
- for(j=0;j<=m;j++)
- {
- d[i][j]=0;
- dp[i][j]=-1u>>1;
- }
- d[0][0]=dp[0][0]=1;
- for(i=1;i<=n;i++)
- d[i][1]=dp[i][1]=(s[i]%10+10)%10;
- for(j=2;j<=m;j++)
- for(i=j;i<=n;i++)
- for(k=j-1;k<i;k++)
- {
- d[i][j]=max(d[i][j],d[k][j-1]*(((s[i]-s[k])%10+10)%10));//第k+1個數到第i個數分到第j部分
- dp[i][j]=min(dp[i][j],dp[k][j-1]*(((s[i]-s[k])%10+10)%10));
- }
- Max=max(Max,d[n][m]);
- Min=min(Min,dp[n][m]);
- }
- int main()
- {
- while(scanf("%d%d",&n,&m)==2)
- {
- int i,j,a[105];
- Max=0;
- Min=-1u>>1;
- for(i=1;i<=n;i++)
- {
- scanf("%d",a+i);
- a[n+i]=a[i];
- }
- for(j=0;j<n;j++)
- DP(a+j);
- printf("%d/n%d/n",Min,Max);
- }
- }