目录
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
输出:
6
☀️思路:
第一次直接用前缀和对原数组进行处理,然后遍历所有符合要求的区间的数量进行累加,然后就拿了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;
}