打印比n小的最高位不为0的各位数字不同的正整数的个数。
打表记录1~10000000的满足上诉要求的数字,然后二分。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int sn[800000], id;
bool hash[10];
bool isSN(int num)
{
memset(hash, false, sizeof (hash));
while (num > 0)
{
int tmp = num % 10;
num /= 10;
if (hash[tmp]) return false;
else hash[tmp] = true;
}
return true;
}
void make_sn()
{
id = 1;
for (int i = 1; i <= 10000000; i++)
if (isSN(i)) sn[id++] = i;
sn[id] = 10234567;
}
int BSearch(int num)
{
int l = 1, r = id, mid;
while (l < r) {
mid = (l + r) >> 1;
if (sn[mid] == num) return mid;
else if (sn[mid] < num) l = mid + 1;
else r = mid;
}
return l;
}
int main()
{
int n;
make_sn();
while (scanf ("%d", &n) != EOF)
printf ("%d\n", BSearch(n) - 1);
return 0;
}
几乎纯组合数学,TLE 囧。。。
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
int digits[10];
bool hash[10];
int getLen(int num)
{
int l = 0;
while (num != 0) {
num /= 10; l++;
}
return l;
}
void convert(int num)
{
int id = 0;
while (num != 0)
{
digits[id++] = num % 10;
num /= 10;
}
}
int isSN(int num)
{
memset (hash, false, sizeof (hash));
convert (num);
int len = getLen (num);
for (int i = len - 1; i >= 0; i--)
{
if (hash[digits[i]]) return i + 1;
else hash[digits[i]] = true;
}
return -1;
}
int main()
{
int num, i, j;
while (scanf ("%d", &num) != EOF)
{
int res, tmp;
bool flag = false;
while (true) {
res = isSN(num);
if (res == -1) break;
flag = true;
tmp = (int)pow(10.0, res-1.0);
num = num - num % tmp - 1;
}
int ans = 0, cnt, len = getLen(num);
if (len == 1) { printf ("%d\n", num - 1); continue; }
for (i = 0; i < len; i++)
{
memset(hash, false, sizeof (hash));
if (i == 0) tmp = 1;
else tmp *= 10 - len + i;
for (j = i + 1; j < len; j++) hash[digits[j]] = true;
for (cnt = 0, j = digits[i] - 1; j >= 0; j--)
{
if (i == len - 1 && j == 0) break;
if (!hash[j]) cnt++;
}
ans += tmp * cnt;
}
int m = 1;
tmp = 1;
for (i = 0; i < len - 2; i++) {
tmp = tmp * (9 - i);
m += tmp;
}
ans += 9 * m;
if (flag) ans++;
printf ("%d\n", ans);
}
return 0;
}