100可以表示为带分数的形式:100=3+69258/714还可以表示为:100=82+3546/197.
注意特征:带分数中,数字 1∼9分别出现且只出现一次(不包含 0)。类似这样的带分数,100有 11种表示法。
输入格式
一个正整数。
输出格式
输出输入数字用数码 1∼9不重复不遗漏地组成带分数表示的全部种数。
数据范围
1≤N<10^6
输入样例1:
100
输出样例1:
11
输入样例2:
105
输出样例2:
6
思路
- 很暴力的方法,先搞出来1-9的全排列,再隔两个版,然后算一下符不符合答案,就行。
- 比较优化的方法是把式子看成n = a + b / c, 可以得到n * c = a * c + b, 然后枚举a,在a的递归树的叶子处再搜索c,然后通过a和c算出b,检查b是否满足条件(1~9全取遍,不重不漏)。
暴力代码
#include<iostream>
using namespace std;
const int N = 20;
int st[N];
int n, cnt;
int res[N];
int get(int l, int r){
int ans = 0;
while(l <= r){
ans = ans * 10 + res[l];
l ++;
}
return ans;
}
void dfs(int k){
if(k == 9){
for(int i = 0; i < k; i ++)
for(int j = i + 1; j < k - 1; j ++){
int a = get(0, i), b = get(i + 1, j), c = get(j + 1, k - 1);
if(b % c == 0 && a + b / c == n) cnt ++;
}
return;
}
for(int i = 1; i <= 9; i ++){
if(st[i] == 0){
st[i] = 1;
res[k] = i;
dfs(k + 1);
st[i] = 0;
}
}
}
int main(){
cin >> n;
dfs(0);
cout << cnt << endl;
}
优化代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 20;
int n;
int st[N], backup[N];
int cnt;
int check(int a, int c){
memcpy(backup, st, sizeof st);
int b = (n - a) * c;
while(b){
int x = b % 10;
b /= 10;
if(backup[x] || x == 0) return 0;
backup[x] = 1;
}
for(int i = 1; i <= 9; i ++)
if(backup[i] == 0) return 0;
return 1;
}
void dfs_c(int a, int c, int u){
if(u == n) return;
if(check(a, c)) cnt ++;
for(int i = 1; i <= 9; i ++){
if(st[i] == 0){
st[i] = 1;
dfs_c(a, c * 10 + i, u + 1);
st[i] = 0;
}
}
}
void dfs_a(int a, int u){
if(a >= n) return;
if(a) dfs_c(a, 0, u);
for(int i = 1; i <= 9; i ++){
if(st[i] == 0){
st[i] = 1;
dfs_a(a * 10 + i, u + 1);
st[i] = 0;
}
}
}
int main(){
cin >> n;
dfs_a(0, 0);
cout << cnt;
}