题目链接:http://codeforces.com/contest/686/problem/C
题目大意:
给你两个十进制的数n和m,选一个范围在[0,n)的整数a,选一个范围在[0,m)的整数b,要求a的7进制表示和b的7进制表示中的每一位都不重复。其中,a的7进制位数和n-1的7进制位数相同,b的位数和m-1的位数相同。
比如,当n=2,m=3时,a和b的其进制表示的所有集合是:
a=0, b=1
a=0, b=2
a=1, b=0
a=1, b=2
解法:
这套题目可以用dfs做。
我们开一个数组f[],f[i]表示数字i有没有在a和b的七进制表示中出现过。
然后我们遍历a和b的每一位,如果在判断这个数的第i位的时候恰好f[i]=false,我们就可以将f[i]设为true,并将这一位的值设成i,然后继续搜索。
假设我们已经通过搜索得到了a,此时边有一个确定的a(a不是我们答案里需要的,但是我们搜索的过程中实际上会遍历得到所有合法的a)以及一个确定的f[]数组。此时按照dfs_m()函数求得b(b也不是答案里需要的),如果b合法,则ans++(ans是最终答案)。
dfs_m()函数如下(用它来得到b):
void dfs_m(int tmp, int tm) { if (tmp >= m) return; if (tm < 0) { ans ++; return; } for (int i = 0; i < maxn; i ++) { if (f[i] == false) { f[i] = true; dfs_m(tmp + i * g[tm], tm-1); f[i] = false; } } }
我们已经有了dfs_m()了,那么只要我们在找b之前找到每一个a就行了,找a的方法也是dfs,如下的dfs_n()方法:
void dfs_n(int tmp, int tn) { if (tmp >= n) return; if (tn < 0) { dfs_m(0, mm-1); return; } for (int i = 0; i < maxn; i ++) { if (f[i] == false) { f[i] = true; dfs_n(tmp + i * g[tn], tn-1); f[i] = false; } } }
完整代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 7; bool f[maxn]; int g[maxn], n, m, nn, mm; long long ans = 0; void init() { memset(f, false, sizeof(f)); g[0] = 1; for (int i = 1; i < maxn; i ++) g[i] = g[i-1] * 7; } int chk(int n) { if (n == 1) return 1; n -= 1; int cnt = 0; while (n) { n /= 7; cnt ++; } return cnt; } void dfs_m(int tmp, int tm) { if (tmp >= m) return; if (tm < 0) { ans ++; return; } for (int i = 0; i < maxn; i ++) { if (f[i] == false) { f[i] = true; dfs_m(tmp + i * g[tm], tm-1); f[i] = false; } } } void dfs_n(int tmp, int tn) { if (tmp >= n) return; if (tn < 0) { dfs_m(0, mm-1); return; } for (int i = 0; i < maxn; i ++) { if (f[i] == false) { f[i] = true; dfs_n(tmp + i * g[tn], tn-1); f[i] = false; } } } int main() { scanf("%d%d", &n, &m); init(); if (n > m) swap(n, m); nn = chk(n); mm = chk(m); if (nn + mm > 7) { puts("0"); return 0; } dfs_n(0, nn-1); cout << ans << endl; return 0; }