説明
解決
条件を満たすyydの数は、実際にはnnと同じです。n(タイトルの意味ではありません)は等差数列の式と密接に関連している
ため、特定の値を2つに分割できます
。最終的な回答の値の範囲は[、)[、)に拡大する必要があります。[ 、)、左側が閉じて右側が開いて
おり、2つの境界は差が最小の境界である必要があります1 11、次いで回答のバイナリ態様は、固定されており、
同じことに分割され、1
ここで、 1の特定の位置を組み合わせの数と関連付けることができます。これにより、少数の組み合わせを前処理して、クエリ時間の複雑さを軽減できます。
個人的にはまだ考えるのは難しいと思います!
コード
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
#define MAX 1e18
#define ll long long
#define mod 998244353
ll c[3005][3005];
ll qkpow1( ll x, ll y ) {
ll ans = 1;
while( y ) {
if( y & 1 ) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
ll qkpow2( ll x, ll y ) {
ll ans = 1;
while( y ) {
if( y & 1 ) ans *= x;
x *= x;
y >>= 1;
}
return ans;
}
ll calc( ll n ) {
return n * ( n + 1 ) >> 1;
}
ll C( ll n, ll m ) {
if( n <= 3000 && m <= 3000 ) return c[n][m];
if( m > n - m ) m = n - m;
if( n >= 1e7 && m >= 3 ) return MAX + 1;
__int128 d1 = 1, d2 = 1;
for( int i = 1;i <= m;i ++ ) d1 *= i;
for( int i = n - m + 1;i <= n;i ++ ) {
d2 *= i;
if( d2 > d1 * MAX ) return MAX + 1;
}
return d2 / d1;
}
void solve( ll n, ll k, ll ans ) {
ll t = 0, tmp;
while( k > ( tmp = C( n, t ) ) ) k -= tmp, t ++;
int last = n;
for( ll i = 1;i <= t;i ++ ) {
ll l = 1, r = last, pos;
while( l <= r ) {
ll mid = ( l + r ) >> 1;
if( C( mid - 1, t - i + 1 ) < k ) pos = mid, l = mid + 1;
else r = mid - 1;
}
last = pos - 1;
k -= C( pos - 1, t - i + 1 );
ans = ( ans + qkpow1( 2, pos - 1 ) ) % mod;
}
printf( "%lld\n", ans );
}
void init( int n = 3000 ) {
for( int i = 0;i <= n;i ++ )
for( int j = 1;j <= i;j ++ )
c[i][j] = MAX + 1;
for( int i = 0;i <= n;i ++ ) {
c[i][0] = 1;
for( int j = 1;j <= i;j ++ )
c[i][j] = min( c[i][j], c[i - 1][j] + c[i - 1][j - 1] );
}
}
int main() {
init();
int T; ll n, k;
scanf( "%d", &T );
while( T -- ) {
scanf( "%lld %lld", &n, &k );
ll t = sqrt( n << 1 );
while( calc( t ) > n ) t --;
ll t1 = n - calc( t ), t2 = t - t1;
if( ! t1 ) {
if( k == 1 ) printf( "%lld\n", ( qkpow1( 2, t ) - 1 + mod ) % mod );
else printf( "-1\n" );
}
else if( t2 < 60 && qkpow2( 2, t2 ) < k )
printf( "-1\n" );
else solve( t2, k, ( qkpow1( 2, t1 ) - 1 + mod ) % mod * qkpow1( 2, t2 + 1 ) % mod );
}
return 0;
}