題目描述 丁丁最近沉迷於一個數字游戲之中。這個游戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個游戲並不那麼容易。游戲是這樣的,在你面前有一圈整數(一共n個),你要按順序將其分為m個部分,各部分內的數字相加,相加所得的m個結果對10取模後再相乘,最終得到一個數k。游戲的要求是 ...
題目描述
丁丁最近沉迷於一個數字游戲之中。這個游戲看似簡單,但丁丁在研究了許多天之後卻發覺原來在簡單的規則下想要贏得這個游戲並不那麼容易。游戲是這樣的,在你面前有一圈整數(一共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行每行有個整數,其絕對值不大於104,按順序給出圈中的數字,首尾相接。
輸出格式:
輸出文件有兩行,各包含一個非負整數。第一行是你程式得到的最小值,第二行是最大值。
輸入輸出樣例
輸入樣例#1: 複製4 2 4 3 -1 2輸出樣例#1: 複製
7 81
$DpMin[i][j][k]$表示$i$到$j$中切了$k$次的最小值
$DpMax$表示最大值
轉移的時候枚舉斷點
左右兩邊相乘
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=2001; const int INF=0x7fffff; inline char nc() { static char buf[MAXN],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++; } inline int read() { char c=nc();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();} return x*f; } int DpMin[101][101][11]; int DpMax[101][101][11]; int a[MAXN]; int Query(int a) { return ((a%10)+10)%10; } int main() { #ifdef WIN32 freopen("a.in","r",stdin); #else #endif int n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i]; for(int i=1;i<=2*n;i++) a[i]+=a[i-1]; for(int l=1;l<=2*n;l++) for(int r=l;r<=2*n;r++) DpMin[l][r][1]=DpMax[l][r][1]=Query(a[r]-a[l-1]); for(int i=2;i<=m;i++) for(int l=1;l<=2*n;l++) for(int r=l+i-1;r<=2*n;r++) DpMin[l][r][i]=INF; for(int i=2;i<=m;i++)//已經切了k次 for(int l=1;l<=2*n;l++) for(int r=l+i-1;r<=2*n;r++) for(int k=l+i-2;k<r;k++) { DpMin[l][r][i]=min(DpMin[l][r][i],DpMin[l][k][i-1]*Query(a[r]-a[k])); DpMax[l][r][i]=max(DpMax[l][r][i],DpMax[l][k][i-1]*Query(a[r]-a[k])); } int AnsMax=0,AnsMin=INF; for(int i=1;i<=n;i++) AnsMax=max(AnsMax,DpMax[i][i+n-1][m]), AnsMin=min(AnsMin,DpMin[i][i+n-1][m]); printf("%d\n%d",AnsMin,AnsMax); return 0; }