[Zhengrui 2021 winter vacation provincial election second round of training day 1] Token generation (number of combinations + two points)

description

Insert picture description hereInsert picture description here

solution


Insert picture description hereInsert picture description hereThe number of yyds that meet the conditions is actually the same as nnn (not the meaning of the title) is inextricably linked to the arithmetic sequence formula,
so the specific value can be divided into two
. The value range of the final answer must grow into[,) [,)[,) , the left is closed and the right is opened,
and the two boundaries must be the one with the smallest difference1 11 , then the binary aspect of the answer is also fixed and the
Insert picture description here
same is divided into1 1The specific position of 1 can be
linked here with the number of combinations, which can preprocess a small number of combinations to reduce query time complexity

Privately think that it is still difficult to think!

code

#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;
}

Guess you like

Origin blog.csdn.net/Emm_Titan/article/details/113893715