参照了nocow上的解法,照搬过来……
易知一个数X在数列中在另一个数Y前,当且仅当X前缀小于Y或前缀相等X短,那么我们分布考虑,比如对于数48561:
5位上:10000~48560;
4位上:1000~4856;
3位上:100~485;
2位上:10~48;
1位上:1~4.
这样我们就得到了1..N中4856的位置,可以用这个来判错.
接下来的方法类似,为了使得我们的N满足要求,我们必须去找比48561大且前缀比其小的数,同样有:
6位上:100000~48569; //注意红色部分比原数减少了1,之前没注意这里一直WA……
……
---------------------以上nocow上给出的题解-----------------------
判断无解的情况:
1.当K != 10^x 时,假设到 K 时前面已经有的数的个数是cnt,如果 M - 1 < cnt 则无解。
2.当K == 10^x 时,K前面最多只有x个数,M - 1 > x 则无解。
一组数据:
1150 27350
12 2
20 13
3 23
3 3
100 3
输出:
1010679
0
20
29
3
100
#include <cstdio>
#include <cstring>
#include <cstdlib> #define LL unsigned long long int using namespace std; const int MAXN = ; LL K, M, cnt;
LL bit[MAXN];
char strK[MAXN], strM[MAXN];
bool ok, find; void init()
{
bit[] = ;
for ( int i = ; i < MAXN; ++i )
bit[i] = bit[i - ] * (LL);
return;
} void chuli()
{
cnt = ;
int len = strlen( strK );
for ( int i = ; i <= len; ++i )
{
//printf( "###%I64u %I64u\n", K / bit[ len - i ], bit[i - 1] );
cnt += K / bit[ len - i ] - bit[i - ] + ;
}
--cnt;
//printf("**%I64u %I64u\n", cnt, M );
if ( cnt > M - ) ok = false;
return;
} LL GetAns()
{
LL cur = K; if ( cnt == M - ) return cur;
--cur; int i;
for ( i = strlen(strK); ; ++i )
{
cur = cur * + ;
//printf( "~~~%20I64u %20I64u\n", cur, bit[i] );
LL tmp = cnt + cur - bit[i] + ;
//printf( "tmp=%I64d\n", tmp );
if ( tmp == M - ) return cur;
if ( tmp >= M ) break;
cnt = tmp;
} return bit[i] + M - - cnt - ;
} bool SpecialJudge()
{
int len = strlen(strK);
find = false;
for ( int i = ; i <= len; ++i )
{
if ( K == bit[i] )
{
find = true;
break;
}
}
if ( !find ) return true;
if ( M - > cnt ) return false;
return true;
} int main()
{
//freopen( "out.txt", "r", stdin );
//freopen( "s1.txt", "w", stdout );
init();
while ( scanf( "%s", strK ) == )
{
scanf( "%I64u", &M );
sscanf( strK, "%I64u", &K ); ok = true;
LL ans;
chuli(); if ( !SpecialJudge() )
{
puts("");
continue;
}
if ( find )
{
if ( cnt == M - ) printf( "%I64u\n", K );
else puts("");
continue;
} if ( ok ) ans = GetAns();
if ( ok ) printf( "%I64u\n", ans );
else puts("");
}
return ;
}