按照别人的思路敲得。。。。自己太渣了。。。。参考的是《数位计数问题解法研究 清华附中 高逸涵》这篇论文。。。。。
解题思路:
AC代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;
long long dp1[20][200];//dp1[k][sum] : k位数字之和为sum的数字的个数
//初始化
void init(){
memset( dp1, -1, sizeof( dp1 ) );
}
//计算k位数字之和为sum的数字的个数
long long getsum1( int k, int sum ){
if( k <= 0 ){
return sum == 0;
}
if( dp1[k][sum] != -1 ){
return dp1[k][sum];
}
long long ans = 0;
for( int i = 0; i <= 9; i++ ){
ans += getsum1( k - 1, sum - i );
}
return dp1[k][sum] = ans;
}
//计算1到N中各位数字之和为sum的个数
long long getsum2( long long N, int sum ){
int digit[20], L = 0;
long long p = N;
while( p ){
digit[++L] = p % 10;
p /= 10;
}
long long ans = 0;
for( int i = L; i > 0; i-- ){
for( int j = 0; j < digit[i]; j++ ){
ans += getsum1( i - 1, sum-- );
}
}
ans += getsum1( 0, sum );
return ans;
}
//1-n中前缀为prefix各位数之和为sum的数字的个数
long long getsum3( long long n, long long prefix, int sum ){
char sn[20], sp[20];
int ln = sprintf( sn, "%lld", n );
int lp = sprintf( sp, "%lld", prefix );
for( int i = 0; i < lp; i++ ){
sum -= sp[i] - '0';
}
int i;
for( i = 0; i < lp; i++ ){
if( sp[i] != sn[i] ){
break;
}
}
if( i < lp ){
long long ans = 0;
if( sp[i] > sn[i] ){
ln--;
}
for( i = ln - lp; i >= 0; i-- ){
ans += getsum1( i, sum );
}
return ans;
}
long long ans = 0, temp = 0;
for( i = lp; i < ln; i++ ){
temp = temp * 10 + sn[i] - '0';
}
ans += getsum2( temp, sum );
for( i = ln - lp - 1; i>= 0; i-- ){
ans += getsum1( i, sum );
}
return ans;
}
//1-n中字典序小于k的各位和为sum的数的个数
long long getsum4( long long n, long long k, int sum ){
int digit[20], len = 0;
long long ans = 0;
while( k ){
digit[++len] = k % 10;
k /= 10;
}
long long prefix = 1;
int t = 1;
for( int i = len; i >= 1; i-- ){
for( int j = t; j < digit[i]; j++ ){
ans += getsum3( n, prefix++, sum );
}
prefix *= 10;
t = 0;
}
for( int i = 1; i <= len; i++ ){
if( digit[i] == 0 ){
ans++;
}else{
break;
}
}
return ans;
}
//k在1-n中的位置
long long getsum5( long long n, long long k ){
long long ans = 0;
int sum = 0;
long long temp = k;
while( temp ){
sum += temp % 10;
temp /= 10;
}
for( int i = 1; i < sum; i++ ){
ans += getsum2( n, i );
}
ans += getsum4( n, k, sum );
return ans + 1;
}
int main(){
long long N, K;
init();
while( cin >> N >> K && !( N == 0 && K == 0 ) ){
cout << getsum5( N, K ) << " ";
int sum = 1;
long long t;
while( ( t = getsum2( N, sum ) ) < K ){
sum++;
K -= t;
}
long long pre = 1;
int presum = 1;
while( true ){
while( ( t = getsum3( N, pre, sum ) ) < K ){
presum++;
pre++;
K -= t;
}
if( presum == sum ){
break;
}else{
pre *= 10;
}
}
while( --K ){
pre *= 10;
}
cout << pre << endl;
}
return 0;
}
/*
bool check_getsum1( int k, int sum ){
long long end = 1;
for( int i = 1; i <= k; i++ ){
end *= 10;
}
end -= 1;
long long ans = 0;
for( long long i = 0; i <= end; i++ ){
long long p = i;
long long tempsum = 0;
while( p ){
tempsum += p % 10;
p /= 10;
}
if( tempsum == sum ){
ans++;
}
}
if( ans == getsum1( k, sum ) ){
return true;
}else{
return false;
}
}
*/