第四届蓝桥杯省赛 C++ B组 - 带分数

✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:蓝桥杯题解集合
📝原题地址:带分数
📣专栏定位:为想参加蓝桥杯的小伙伴整理常考算法题解,祝大家都能取得理想成绩!
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

问题描述

100 可以表示为带分数的形式:100=3+69258/714

还可以表示为:100=82+3546/197

注意特征:带分数中,数字 1∼9 分别出现且只出现一次(不包含 0)。

类似这样的带分数,100 有 11 种表示法。

输入格式

一个正整数。

输出格式

输出输入数字用数码 1∼9 不重复不遗漏地组成带分数表示的全部种数。

数据范围

1≤N<106

输入样例1:
100
输出样例1:
11
输入样例2:
105
输出样例2:
6

暴力法

#include <bits/stdc++.h>
using namespace std;

int n;
const int N = 10;
int res[N]; //存储结果
bool st[N]; //表示元素是否用过
int cnt = 0;

//计算每一段的总数
int calc(int l, int r) {
	int num = 0;
	for (int i = l; i <= r; i++) {
		num = num * 10 + res[i];
	}
	return num;
}

//将全排列的数组分成三段进行判断
void dfs(int k) {
	if (k == 9) {
		for (int i = 0; i < 7; i++) {
			for (int j = i + 1; j < 8; j++) {
				int a = calc(0, i);
				int b = calc(i + 1, j);
				int c = calc(j + 1, 8);
				if (a * c + b == n * c) //c++中除法是整除,所以要转换为乘法
					cnt++;
			}
		}
		return;
	}
	//进行全排列
	for (int i = 1; i <= 9; i++) {
		if (!st[i]) {
			st[i] = true;
			res[k] = i;
			dfs(k + 1);
			st[i] = false;
		}
	}
}

int main() {
	cin >> n;
	dfs(0);
	cout << cnt << endl;
	return 0;
}

暴力法(内置函数)

next_permutation() 蓝桥杯允许使用

#include<bits/stdc++.h>
using namespace std;

int n;
const int N=10;
int res[N]; //存储结果
int cnt=0;

//计算每一段的总数
int calc(int l,int r)
{
    int num=0;
    for(int i=l;i<=r;i++)
    {
        num=num*10+res[i];
    }
    return num;
}

int main()
{
    cin>>n;
    for(int i=0;i<9;i++)
        res[i]=i+1;
    do{
        for(int i=0;i<7;i++)
        {
            for(int j=i+1;j<8;j++)
            {
                int a=calc(0,i);
                int b=calc(i+1,j);
                int c=calc(j+1,8);
                if(a*c+b==n*c)
                    cnt++;
            }
        }
    }while(next_permutation(res,res+9));	//调用函数进行全排列
    cout<<cnt<<endl;
    return 0;
}

优化

先枚举 a ,再枚举 c ,直接通过 a 和 c 求出 b ,就不用再枚举 b 了。然后判断 b 是否满足要求,如果 b 中的每一位都没有被 a 和 c 所用过并且 1 到 9 都被已经用过了,则满足要求,答案总数加 1。

举个例子,假设 a 枚举到了 82,然后枚举 c,而 c 枚举到了 3456,则去计算 b,根据公式推导,b 等于 n*c-a*c,从而算出 197。接下来就进行判断,首先 abc 都不能为 0 这是肯定的,然后需要判断 b 是否用了剩下没有用过的数字,如果出现了 a 和 c 中的数字则不满足条件,并且 b 要将剩下没用过的数字全部用上才满足条件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EgJlNhdS-1675500728387)(AcWing 蓝桥杯辅导.assets/6-1.png)]

#include <bits/stdc++.h>
using namespace std;

const int N = 10;
int n, ans = 0;
bool st[N], backup[N];

//判断是否满足条件
bool check(int a, int c) {
    //计算b
    //这里需要long long是因为防止n为10的6次方时与c相乘后爆int,导致b为负数,x也会为负数
    //x为负数的话,backup就会数组越界,所以要加long long
	long long b = n * (long long)c - a * c;
	//a,b,c都不能为0
	if (!b || !a || !c)
		return false;
	//因为原状态数组不能改变,为了后续判断,就新建一个状态数组用于判断
	memcpy(backup, st, sizeof(st));
    //判断b中的每一位数字
	while (b) {
		int x = b % 10;
		if (!x || backup[x])
			return false;
		b /= 10;
		backup[x] = true;
	}
	//判断是否1-9都使用过
	for (int i = 1; i <= 9; i++) {
		if (!backup[i])
			return false;
	}
	return true;
}

//枚举c
void dfs_c(int x, int a, int c) {
	if (x > 9)
		return;

	if (check(a, c))
		ans++;

	for (int i = 1; i <= 9; i++) {
		if (!st[i]) {
			st[i] = true;
			dfs_c(x + 1, a, c * 10 + i);
			st[i] = false;
		}
	}
}

//枚举a
void dfs_a(int x, int a) {
	if (a >= n)
		return;

	if (a)
		dfs_c(x, a, 0);

	for (int i = 1; i <= 9; i++) {
		if (!st[i]) {
			st[i] = true;
			dfs_a(x + 1, a * 10 + i);
			st[i] = false;
		}
	}
}

int main() {
	cin >> n;
	dfs_a(0, 0);
	cout << ans << endl;
	return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值