Hallo,小伙伴们!没错!又是我——永遇乐,不知不觉就已经第九天了,今天我继续带领你们解答蓝桥杯的题目。俗话说得好:冰冻三尺非一日之寒,所以我们做题也要持之以恒呀!各位小伙伴,你们准备好与我共同继续前行了吗?
今天有四道题目,也不算太难,没涉及什么算法,主要是模拟和数学。让我们遨游于题海中吧!
博主看到的时候就心想:这怎么和昨天的神奇算式这么像!!!
神奇算式 原题及题解传送门
打眼儿一看,这是一道模拟题,这道题目要求我们式子左边的两个数共包含1~9,9位数字,式子右边要求我们也是9位数(1~9不同的数字),所以我们需要用数组判定两边的数位中是否出现相同的数,而且我们看到例子中的9*87146325 = 784316925,看到这个乱序的数,我们想到了什么?没错!就是C++中的全排列函数,到这里我们成功了一大半了。题目问的是乘积最大是多少,我们当然会不自主地想到max函数。到这里,本题就已经分析完毕,接下来让我们看看具体如何实现吧!
#include
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
LL maxn;
int a[10]= {0,1,2,3,4,5,6,7,8,9},b[10];//a用于全排列,b用于判断数位上的数是否有重复
bool check() {
for(int i=1; i<=9; i++)
if(b[i]==0) return false;
return true;
}
int main() {
do {
for(int i=1; i<9; i++) {
LL s1=0,s2=0;
memset(b,0,sizeof(b));//清零
for(int j=1; j<=i; j++)
s1=s1*10+a[j];//从9位数中的8处地方的某一处划分成两个数
for(int j=9; j>i; j--)
s2=s2*10+a[j];
//cout<
小伙伴们,看到100!的瞬间傻眼了吧?博主当时也傻了,这100!多大不说,还要我求有几个正约数,这该咋求啊?算出来再一个一个去求?那根本不可行呀!long long也只能存到20!,所以我们肯定不用这个方法,所以我在网上查了一下,发现两个定理:唯一分解定理和约数和定理。
大概意思就是任意大于1的数都能通过素数相乘而得到。
约数和定理:对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,则由 约数个数定理可知n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个。
通过以上两个定理,这题就变得非常简单了。100!=1*2*......*100,那么我们可以将其中的非素数通过分解质因数变成素数,这样就符合唯一分解定理了,然后用数组存储这些素数的个数,到最后用一个for配合约数和定理便大功告成了。
#include
using namespace std;
typedef long long LL;
int a[100];
LL s=1;
int main() {
for(int i=2; i<=100; i++) { //唯一分解定理
int j=i;
for(int k=2; k<=j; k++) { //分解质因数
while(j%k==0) {
a[k]++; //存储分解出素数的个数
j/=k;
}
}
}
for(int i=2; i<=100; i++)
if(a[i]>0) s=s*(1+a[i]); //约数和定理
cout<
这是一道非常简单的模拟题,就是枚举1900年1月1日到9999年12月31日的所有日期,并判定年月日中是否含2这个数字,注意判断闰年。
#include
#include
#include
using namespace std;
int date[]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
int sum=0;
bool check(int n) {
while(n) {
if(n%10==2) return true;
n/=10;
}
return false;
}
int main() {
for(int year=1900; year<=9999; year++) {
if(year%400==0 || (year%4==0 && year%100!=0)) date[2]=29; //闰年
else date[2]=28;
for(int month=1; month<=12; month++)
for(int day=1; day<=date[month]; day++) {
if(check(year) || check(month) || check(day)) sum++;
}
}
cout<
输出:6
这道题是一道典型的前缀和和同余定理的题目,你也可以理解为是一道数学题。小伙伴们可能并不知道前缀和和同余定理是什么,下面我给大家科普一下。
一维前缀和:假设x1,x2,...,xn是元素,y1,y2,...yn是存储前缀和的容器,那么y1=x1, y2=x1+x2, y3=x1+x2+x3,y4=x1+x2+x3+x4,...yn=x1+x2+x3+...+xn,像这样关系的就是一维前缀和。为什么我要说这是一维前缀和呢?因为还有二维的,三维的,甚至n维的。
同余定理:《离散数学》中是这样定义的: 设m是正整数,a和b是整数.如果m | a-b,则称a模m同余于b,或a与b模m同余.其充要条件是:a与b除以m的余数相等,即a mod m = b mod m。
题目说到连续子序列,也就是[1,5],[1,2],[2,3],[10,100]......形如这样的序列。而前缀和为什么适用于本题,例如:[1,5]则S5,[5,9]则S9-S4,这里面的Si都是前缀和(前i个数相加)。题中说到连续子序列之和是k的倍数,则称其为k倍区间,问有几个。
用样例举例吧。样例输入5个数,k=2,也就是连续子序列之和要是2的倍数。前缀和就是s1=1, s2=3, s3=6, s4=10, s5=15,那么哪里用到了同余定理呢?
我们仔细观察一下,s1,s2,s5都是除以2余1,s3,s4除以2余0,这说明什么?说明:s2-s1, s5-s1, s5-s2, s3, s4, s4-s3 都是k倍区间。s2-s1=2, s5-s1=14,正好就是2的倍数。
因此我们可以先求得前缀和,再找出前缀和相同的余数有几个,再将其分类相加。这里注意一下,s1,s2,s5是余1,共3个,即(n-1)*n/2个;而s3,s4余0,也就是本身也是2的倍数,所以也有3个,即(n+1)*n/2个。
#include
#include
#include
using namespace std;
typedef long long LL;
int n,k;
int a[100005];
LL s[100005],sum[100005],cnt;
int main() {
cin>>n>>k;
for(int i=1; i<=n; i++) {
cin>>a[i];
s[i]=s[i-1]+a[i]; //前缀和
}
for(int i=1; i<=n; i++)
sum[s[i] % k]++; // 算同余的个数
for(int i=0; i