(mathcal{Description})
Link.
给定 (n) 和 (q) 次询问,每次询问给出 (x,k),求第 (x) 位为 0
且任意两个 1
的下标之差不小于 (k) 的长度为 (n) 的 01 序列数量。
(n,qle10^5)。
(mathcal{Solution})
“不小与 (k)”可能在复杂度中体现为“(div k)”,考虑根号分治。
对于 (klesqrt n),预处理 (f(k,i)) 表示不考虑 (x) 的限制,长度为 (i) 的序列数量。通过全局答案减去 (x) 位为 1
的答案可以 (mathcal O(1)) 回答询问;
而对于 (k>sqrt n),1
的数量 (lesqrt n),枚举 1
的数量,把 0{k-1}1
看做一整块,可以隔板法求方案,在用总方案减去左右方案之积即可 (mathcal O(sqrt n)) 回答询问。
最终,得到复杂度最坏为 (mathcal O((n+q)sqrt n)) 的算法。
(mathcal{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
", 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
", sub( all, mul( lcnt, rcnt ) ) );
}
}
return 0;
}