1923:【03NOIP普及组】数字游戏
【题目描述】
丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共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,按顺序给出圈中的数字,首尾相接。
【输出】
有两行,各包含一个非负整数。第一行是你程序得到的最小值,第二行是最大值。
【输入样例】
4 2
4
3
-1
2
【输出样例】
7
81
题解
我用深搜作了这道题,不算难,过程就在代码里告诉大家了
#include<cstdio>
#include<algorithm>//算法库,有max和min
using namespace std;
const int MAXN=110;
const int INF=0x3f3f3f3f;//定义成2e9或2147483647也行
const int n9[9]={9,81,729,6561,59409,531441,4782969,43046721,387420489};//m<=9,打个表就好了
int n,m;
int a[MAXN];
int ansmin=INF,ansmax=0;//最小和最大,都要初始化
int mod10(int x){//计算模10的函数
return (x%10+10)%10;
}
void dfs(int depth,int now,int value){//重磅dfs
if(value>=ansmin&&value*n9[m-depth]<=ansmax) return;//剪枝
int sum=0;
if(depth==m){
for(int i=now;i<=n;i++) sum+=a[i];//计算和
ansmin=min(ansmin,value*mod10(sum));//比较
ansmax=max(ansmax,value*mod10(sum));
return;
}
for(int i=now;i<=(n-m+depth);i++){//遍历下一个点
sum+=a[i];//前缀和
dfs(depth+1,i+1,value*mod10(sum));//下一步计算
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i+n]=a[i];//破环成链
}
for(int i=1;i<=n;i++){//枚举初始点
dfs(1,1,1);//都是1,只是巧合
for(int j=1;j<=2*n;j++) a[j]=a[j+1];//往前挪
}
printf("%d\n%d\n",ansmin,ansmax);//输出
return 0;//华丽结束
}