LOJ #562. 「LibreOJ Round #9」Tangjz 的背包

链接:

link

题解:

P = 998244353 , r = 19190506 , q = 1 r ,那么答案就是 r p m [ x m ] i = 0 n 1 ( 1 + q i x )

根据 wiki ,有 [ x m ] i = 0 n 1 ( 1 + q i x ) = q m ( m 1 ) 2 ( n m ) q

定义 [ k ] q = i = 0 k 1 q i = q k 1 q 1 [ n ] q ! = i = 1 n [ i ] q ,那么 ( n m ) q = [ n ] q ! [ m ] q ! [ n m ] q !

注意到 q 1 在分子分母中出现的总次数都相等,那么可以忽视掉。

a q P 的阶, F ( n ) = i = 1 n ( q i 1 ) ,将 F ( n ) 分成两部分,模 P 0 的和不为 0 分别计算,有:

F ( n ) = ( i = 1 n a ( q a i 1 ) ) ( i = 1 , a i n ( q i 1 ) )

对于后面部分是很好计算的,考虑算前面部分:

q a i 1 = ( q a 1 ) ( j = 0 i 1 q a j )

注意到后面那个玩意就是 i ,所以前面部分就是 n a ! ( q a 1 ) n a

如果 n a m a + n m a ,那么答案显然是 0 ,否则消掉 0 之后就是 ( n a m a )

这里 a 大约是 10 6 ,所以 a n a 都不是很大,暴力预处理一些东西就可以了。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 1100000;
const int q = 768906335;
const int r = 19190506;
const int mod = 998244353;
const int period = 917504;

int f[N], g[N], fac[N], ifac[N];

int add(int x, int y) {
  x += y;
  if (x >= mod) {
    x -= mod;
  }
  return x;
}

int mul(int x, int y) {
  return (ll)x * y % mod;
}

int power(int x, int y) {
  int result = 1;
  while (y) {
    if (y & 1) {
      result = mul(result, x);
    }
    x = mul(x, x);
    y >>= 1;
  }
  return result;
}

int binom(int n, int m) {
  return mul(fac[n], mul(ifac[m], ifac[n - m]));
}

int fact(int n, int m) {
  return mul(f[n], mul(g[m], g[n - m]));
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  f[0] = g[0] = 1;
  for (int i = 1, coef = 1; i < period; ++i) {
    coef = mul(coef, q);
    f[i] = mul(f[i - 1], coef - 1);
    g[i] = mul(g[i - 1], power(coef - 1, mod - 2));
  }
  fac[0] = ifac[0] = fac[1] = ifac[1] = 1;
  int limit = (1000000000000ll + period - 1) / period;
  for (int i = 2; i <= limit; ++i) {
    fac[i] = mul(fac[i - 1], i);
    ifac[i] = mul(mod - mod / i, ifac[mod % i]);
  }
  for (int i = 2; i <= limit; ++i) {
    ifac[i] = mul(ifac[i - 1], ifac[i]);
  }
  int T;
  scanf("%d", &T);
  while (T--) {
    ll n, m;
    scanf("%lld %lld", &n, &m);
    if (n / period != m / period + (n - m) / period) {
      puts("0");
      continue;
    }
    int p = ((n - m) % period) * (m % period) % period;
    int answer = power(r, p);
    answer = mul(answer, binom(n / period, m / period));
    answer = mul(answer, fact(n % period, m % period));
    printf("%d\n", answer);
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/wxh010910/article/details/80736601