Live2D

Solution -「多校联训」染色

Description

  Link.

  给定 nq 次询问,每次询问给出 x,k,求第 x 位为 0 且任意两个 1 的下标之差不小于 k 的长度为 n 的 01 序列数量。

  n,q105

Solution

  “不小与 k”可能在复杂度中体现为“÷k”,考虑根号分治。

  对于 kn,预处理 f(k,i) 表示不考虑 x 的限制,长度为 i 的序列数量。通过全局答案减去 x 位为 1 的答案可以 O(1) 回答询问;

  而对于 k>n1 的数量 n,枚举 1 的数量,把 0{k-1}1 看做一整块,可以隔板法求方案,在用总方案减去左右方案之积即可 O(n) 回答询问。

  最终,得到复杂度最坏为 O((n+q)n) 的算法。

Code

/* Clearink */

#include <cmath>
#include <cstdio>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )

const int MAXSN = 316, MAXN = 1e5, MOD = 998244353;
int n, q, thres, f[MAXSN + 5][MAXN + 5], fac[MAXN * 2 + 5], ifac[MAXN * 2 + 5];

inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
inline int mul( const long long a, const int b ) { return int( a * b % MOD ); }
inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int mpow( int a, int b ) {
	int ret = 1; 
	for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
	return ret;
}

inline void init() {
	fac[0] = 1;
	rep ( i, 1, 2 * n ) fac[i] = mul( i, fac[i - 1] );
	ifac[2 * n] = mpow( fac[2 * n], MOD - 2 );
	per ( i, 2 * n - 1, 0 ) ifac[i] = mul( i + 1, ifac[i + 1] );

	rep ( i, 1, thres ) {
		int* fi = f[i]; *fi = 1;
		rep ( j, 1, n ) fi[j] = add( fi[j - 1], j >= i ? fi[j - i] : 1 );
	}
}

inline int comb( const int n, const int m ) {
	return n < 0 || n < m ? 0 : mul( fac[n], mul( ifac[m], ifac[n - m] ) );
}

int main() {
	freopen( "color.in", "r", stdin );
	freopen( "color.out", "w", stdout );

	scanf( "%d %d", &n, &q ), thres = sqrt( n );

	init();

	for ( int x, k; q--; ) {
		scanf( "%d %d", &x, &k );
		if ( k <= thres ) {
			printf( "%d\n", sub( f[k][n], mul( x >= k ? f[k][x - k] : 1,
				n + 1 >= x + k ? f[k][n - x - k + 1] : 1 ) ) );
		} else {
			int all = 0, lcnt = 0, rcnt = 0;
			rep ( i, 0, ( n + k - 1 ) / k ) {
				all = add( all, comb( n + k - 1 - i * k + i, i ) );
				lcnt = add( lcnt, comb( x - 1 - i * k + i, i ) );
				rcnt = add( rcnt, comb( n - x - i * k + i, i ) );
			}
			printf( "%d\n", sub( all, mul( lcnt, rcnt ) ) );
		}
	}
	return 0;
}

posted @   Rainybunny  阅读(83)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示