D2 hard DistinctDigits
选定一个区间[low,high],将每个数的数字按小到大排序,去掉所有0,构成一个集合。问不同的集合种类。
区间数目相当之大,因此无法从区间各个数来推得答案。考虑到最后一个样例中几近题目最大限度,结果仅为19519,我们可以先搜索集合的种类,然后再逆推是否可组成区间内的数字。
当集合的数字个数小于len(high)大于len(low)时,必然可以得到区间内的某一数字。
当集合的数字个数和high或者low相同时,我们可以继续进行一字符串搜索。
最终最大结果用时1.4s。
int ans;
int maxSize, minSize;
int low, high;
int used[10];
int ac;
string ls, hs, Set;
string itos ( int n )
{
string ret;
while ( n )
ret += ( '0' + n % 10 ), n /= 10;
reverse ( ret.begin (), ret.end () );
return ret;
}
int len ( int n )
{
return n ? len ( n / 10 ) + 1 : 0;
}
void dfss ( string cur )
{
if ( cur.size () == Set.size () )
ac = 1;
if ( ac )
return;
int len = cur.size ();
for ( int i = 0; i < Set.size (); i ++ ) if ( !used[i] )
{
string temp = cur + Set[i];
if ( temp >= ls.substr ( 0, len + 1 ) && temp <= hs.substr ( 0, len + 1 ) )
{
used[i] = 1;
dfss ( temp );
used[i] = 0;
}
}
}
void check ( string s )
{
//cout << s << endl;
if ( s[s.size () - 1] == '0' )
return;
if ( s.size () > minSize && s.size () < maxSize )
{
//cout << s << endl;
ans ++;
return;
}
memset ( used, 0, sizeof ( used ) );
ac = 0;
int h, l;
if ( s.size () == minSize && s.size () == maxSize )
h = high, l = low;
else if ( s.size () == minSize )
{
l = low;
h = 1;
for ( int i = 0; i < s.size (); i ++ )
h *= 10;
h --;
}
else if ( s.size () == maxSize )
{
h = high;
l = 1;
for ( int i = 1; i < s.size (); i ++ )
l *= 10;
}
Set = s, hs = itos ( h ), ls = itos ( l );
dfss ( "" );
if ( ac )
ans ++;
}
void dfs ( string s, int n )
{
string str = s + char ( '0' + n );
if ( str.size () > maxSize )
return;
if ( str.size () >= minSize )
check ( str );
dfs ( str, n );
if ( n < 9 )
dfs ( s, n + 1 );
}
class DistinctDigits
{
public:
int count(int low, int high)
{
ans = 0;
::low = low, ::high = high;
maxSize = len ( high ), minSize = len ( low );
dfs ( "", 0 );
return ans;
}
};