蓝桥冲刺31天打卡—Day9

目录

1.🌟最大乘积

📕题目描述:

☀️思路:

✏️代码 :

二、🌟阶乘约数

📕题目描述:

☀️思路:(写法来自acwing)

代码 

三、🌟含2天数

📕题目描述:

☀️思路:

日期合法性模板 

✏️代码 

四、🌟k倍区间

📕题目描述:

☀️思路: 

✏️前缀和代码(通过部分案例):

✏️AC代码 :


 

1.🌟最大乘积

📕题目描述:

把 1 ~ 9 这 9 个数字分成两组,中间插入乘号, 有的时候,它们的乘积也只包含 1 ~ 9 这 9 个数字,而且每个数字只出现 1 次。

984672 * 351 = 345619872
98751 * 3462 = 341875962
9 * 87146325 = 784316925
...

符合这种规律的算式还有很多,请你计算在所有这些算式中,乘积最大是多少?

注意,需要输出的是一个整数,表示那个最大的积,只输出乘积,不要输出整个算式。

☀️思路:

暴力枚举1~9的全排列,将全排列分成两部分,判断这两部分的乘积是否只包含1~9且无重复数字,找到最大的乘积后输出即可。

答案为:839542176

✏️代码 :

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=10;
int p[N];
bool vis[N];
int st[N];//记录数字使用个数
int ans=0;
int Max;
bool judge(int x){//检查该数字是否只包含1~9且不存在重复数字
	memset(st,0,sizeof(st));
	while(x!=0){
		st[x%10]++;
		x/=10;
	}
	for(int i=1;i<=9;i++){
		if(st[i]!=1){
			return false;
		}
	}
	return true;
}
int f(int l,int r){//l~r范围的数组转换为数字
	int sum=0;
	for(int i=l;i<=r;i++ ){
		sum=sum*10+p[i];
	}
	return sum;
}
void dfs(int u){
	if(u>9){
		for(int i=1;i<=8;i++){//注意这里i上限到8
			int x=f(1,i);
			int y=f(i+1,9);
			if(judge(x*y)){
				Max=max(Max,x*y);
			}
		}
		return;
	}
	for(int i=1;i<=9;i++){//1~9全排列放入p[]
		if(!vis[i]){
			p[u]=i;
			vis[i]=1;
			dfs(u+1);
			vis[i]=0;
		}
	}
}
int main(){
	dfs(1);
	cout<<Max;
	return 0;
}

二、🌟阶乘约数

 题目链接

📕题目描述:

定义阶乘 n! = 1 × 2 × 3 × · · · × n。

请问 100!(100 的阶乘)有多少个正约数。

☀️思路:(写法来自acwing)

数学公式:

任意一个正整数 X 都可以表示成若干个质数乘积的形式,

X = p1^a1*p2^a2*p3^a3......pk^ak

约数个数 ans= (a1 + 1)(a2 + 1)……(ak + 1)

对于每一种pi都有0~ai种选法,一共ai+1种,一共有k个所以乘k次(因为每个pi的指数ai不同就能拼成不同的约数)

例如:12=2*2*3=2^2*3

约数个数就是(2+1)(1+1)=3*2=6

所有约数分别为  1        2        3        4<--2*2        6<--2*3        12<--2*2*3

这题解法就是先对1~100每个数进行分解质因数,再将所有质因数的指数相乘得到答案

答案为:39001250856960000

数据过大使用哈希表存储所有的底数和指数   unorderde_map介绍和用法

 unordered_map<int ,int >primes;

 

代码 

#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N=110;
ll ans=1;
unordered_map<int,int>primes;
int main(){
	for(int i=1;i<=100;i++){
		int x=i;
		for(int j=2;j<=x/j;j++){
			while(x%j==0){
				x/=j;
				primes[j]++;
			}
		}
		if(x>1) primes[x]++;
	}
	for(auto p:primes){
		ans=ans*(p.second+1);
	}
	cout<<ans<<endl;
		
	return 0;
}

三、🌟含2天数

题目链接

📕题目描述:

小蓝特别喜欢 2,今年是公元 2020 年,他特别高兴,因为每天日历上都可以看到 2。

如果日历中只显示年月日,请问从公元 1900 年 1 月 1 日到公元 9999 年 12 月 31 日,一共有多少天日历上包含 2。即有多少天中年月日的数位中包含数字 2。

☀️思路:

直接遍历19000101~99991231找出是合法日期且数位含2的日期并累加。

答案为:1994240

日期合法性模板 

int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int date)//判断日期合法性
{
	int year = date / 10000;  //年
	int month = date % 10000 / 100;  //月
	int day = date % 100;  //日
	if(!month || month > 12 || !day )  return false;//如果月份大于12或者为零或者天数为零则该日期不合法
	if(month != 2 && day > months[month]) return false;//在不是二月的情况下,该月实际天数大于该月最大天数,则该日期不合法
	if(month == 2) //特判二月
	{
		if((year % 4 == 0&& year % 100 != 0) || (year % 400 == 0))//特判闰年
		{
			if(day > 29) return false;
		}
		else if( day > 28) return false;
	}
	return true;
}

✏️代码 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
int  sum;
int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int date)//判断日期合法性
{
	int year = date / 10000;  //年
	int month = date % 10000 / 100;  //月
	int day = date % 100;  //日
	if(!month || month > 12 || !day )  return false;//如果月份大于12或者为零或者天数为零则该日期不合法
	if(month != 2 && day > months[month]) return false;//在不是二月的情况下,该月实际天数大于该月最大天数,则该日期不合法
	if(month == 2) //特判二月
	{
		if((year % 4 == 0&& year % 100 != 0) || (year % 400 == 0))//特判闰年
		{
			if(day > 29) return false;
		}
		else if( day > 28) return false;
	}
	return true;
}
bool f(int   x){//是否含2
	string s=to_string(x);
	
	for(int i=0;i<s.size();i++){
		if(s[i]=='2') return true;
	}
	return false;
}
int main(){
	for(int i=19000101;i<=99991231;i++){
		if(check(i)&&f(i)){//日期是否合法
			sum++;
		}
	}
	printf("%d",sum);// 结果 1994240
	return 0;
}

四、🌟k倍区间

题目链接

📕题目描述:

给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。
你能求出数列中总共有多少个K倍区间吗?

时间限制:1.0s   内存限制:256.0MB

输入格式

  第一行包含两个整数N和K。(1 <= N, K <= 100000)
  以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)

输出格式

  输出一个整数,代表K倍区间的数目。

输入:

  5 2
  1
  2
  3
  4
  5

输出:

☀️思路: 

第一次直接用前缀和对原数组进行处理,然后遍历所有符合要求的区间的数量进行累加,然后就拿了28分。。。

后面进行优化  使用cnt[ ]数组记录所有模k后余数相等的区间的个数进行累加

cnt[i]表示余数是i的个数有多少个
ans表示k倍区间的个数

注意:cnt[0]保存的是i之前余数为0的前缀和的个数在循环之前s[0] % k = 0的个数已经有一个了,所以cnt[0] = 1

 

✏️前缀和代码(通过部分案例):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10 ;
typedef long long ll;
ll n,k;
int ans;
ll a[N];//原数组
ll s[N];//前缀和数组
//s[r]-s[l-1]    [l,r]区间的和
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	s[0]=a[0]=0;
	for(int i=1;i<=n;i++){
		s[i]=s[i-1]+a[i];//前缀和处理
	}
	for(int r=1;r<=n;r++){//枚举右端点
		for(int l=1;l<=r;l++){//枚举左端点
			if((s[r]-s[l-1])%k==0){
				ans++;
			}
		}
	}
	cout<<ans;
	return 0;
}

✏️AC代码 :

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
typedef long long ll;

int n,k;
int a[N];
ll s[N];//前缀和数组
ll cnt[N];//前缀和余数为i的数
int l,r;
ll ans;
int main()
{
	scanf("%d%d", &n, &k);
	
	s[0]=a[0]=0;
	
	for (int i = 1; i <= n; i ++ ){
		scanf("%lld", &a[i]);
		s[i]=s[i-1]+a[i];
	}

	cnt[0]=1;
	for(int i=1;i<=n;i++){
		ans+=cnt[s[i]%k];//加上在此之前与它同余的前缀和
		cnt[s[i]%k]++;//统计前缀和模k后的不同余数出现次数
	}
	
	printf("%lld",ans);
	
	
	return 0;
}

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月色美兮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值