[Zhengrui 2021 vacances d'hiver élection provinciale deuxième tour de la formation jour 1] Génération de jetons (nombre de combinaisons + deux points)

la description

Insérez la description de l'image iciInsérez la description de l'image ici

Solution


Insérez la description de l'image iciInsérez la description de l'image iciLe nombre de yyds qui remplissent les conditions est en fait le même que nnn (pas la signification du titre) est inextricablement lié à la formule de la séquence arithmétique, de
sorte que la valeur spécifique peut être divisée en deux
. La plage de valeurs de la réponse finale doit devenir[,) [,)[ ,) , la gauche est fermée et la droite est ouverte,
et les deux limites doivent être celle avec la plus petite différence1 11 , alors l'aspect binaire de la réponse est également fixe et le
Insérez la description de l'image ici
même est divisé en1 1La position spécifique de 1 peut être
liée ici au nombre de combinaisons, qui peuvent prétraiter un petit nombre de combinaisons pour réduire la complexité du temps de requête

Pensez en privé que c'est encore difficile à penser!

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

Je suppose que tu aimes

Origine blog.csdn.net/Emm_Titan/article/details/113893715
conseillé
Classement