蓝桥杯备赛 | 洛谷做题打卡day25
文章目录
- 蓝桥杯备赛 | 洛谷做题打卡day25
- [NOIP2003 普及组] 数字游戏
- 题目描述
- 输入格式
- 输出格式
- 样例 #1
- 样例输入 #1
- 样例输出 #1
- 提示
- 思路
- 题解代码
- 我的一些话
-
[NOIP2003 普及组] 数字游戏
题目描述
丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共 n n n 个),你要按顺序将其分为 m m m 个部分,各部分内的数字相加,相加所得的 m m m 个结果对 10 10 10 取模后再相乘,最终得到一个数 k k k。游戏的要求是使你所得的 k k k 最大或者最小。
例如,对于下面这圈数字( n = 4 n=4 n=4, m = 2 m=2 m=2):
要求最小值时, ( ( 2 − 1 ) m o d 10 ) × ( ( 4 + 3 ) m o d 10 ) = 1 × 7 = 7 ((2-1)\bmod10)\times ((4+3)\bmod10)=1\times 7=7 ((2−1)mod10)×((4+3)mod10)=1×7=7,要求最大值时,为 ( ( 2 + 4 + 3 ) m o d 10 ) × ( − 1 m o d 10 ) = 9 × 9 = 81 ((2+4+3)\bmod10)\times (-1\bmod10)=9\times 9=81 ((2+4+3)mod10)×(−1mod10)=9×9=81。特别值得注意的是,无论是负数还是正数,对 10 10 10 取模的结果均为非负值。
丁丁请你编写程序帮他赢得这个游戏。
输入格式
输入文件第一行有两个整数, n n n ( 1 ≤ n ≤ 50 1\le n\le 50 1≤n≤50) 和 m m m ( 1 ≤ m ≤ 9 1\le m\le 9 1≤m≤9)。以下 n n n 行每行有个整数,其绝对值 ≤ 1 0 4 \le10^4 ≤104,按顺序给出圈中的数字,首尾相接。
输出格式
输出文件有 2 2 2 行,各包含 1 1 1 个非负整数。第 1 1 1 行是你程序得到的最小值,第 2 2 2 行是最大值。
样例 #1
样例输入 #1
4 2 4 3 -1 2
样例输出 #1
7 81
提示
【题目来源】
NOIP 2003 普及组第二题
思路
DP太难打了,于是选择直接暴力枚举DFS。
主函数
首先,为了枚举环的起点,需要破环为链,开一个2倍空间的数组记录。
枚举起点时,先dfs,再把整个数组往前挪一位,这样就不用管开始位置的问题了。
最后输出答案。
求模10的余数
这个函数有一个细节:如果原数为负数,则%10之后还是负数。(如(-11)%10=-1)
解决方法:先%10(保证不会小于-10),再+10(变成正数),最后%10(正数+10>10)
题解代码
学会利用新知,自己多试试并尝试积攒一些固定解答方案,debug,以下是题解代码 ~
#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;//华丽结束
}
我的一些话
-
今天学习动态规划,dp属于比较难的部分,需要多动脑,多思考思路还是很好掌握的,虽然一次性AC有一定难度,需要通盘的考虑和理解,以及扎实的数据结构基础才能独立写出AC代码。但无论难易,大家都要持续做题,保持题感喔!一起坚持(o´ω`o)
-
如果有非计算机专业的uu自学的话,关于数据结构的网课推荐看b站上青岛大学王卓老师的课,讲的很细致,有不懂都可以私信我喔
-
总结来说思路很重要,多想想,多在草稿纸上画画,用测试数据多调试,debug后成功编译并运行出正确结果真的会感到很幸福!
-
关于之前蓝桥杯备赛的路线和基本方法、要掌握的知识,之前的博文我都有写,欢迎大家关注我,翻阅自取哦~
-
不管什么都要坚持吧,三天打鱼两天晒网无法形成肌肉记忆和做题思维,该思考的时候一定不要懈怠,今天就说这么多啦,欢迎评论留言,一起成长:)