攻防世界 WEB mfw

VINS-Mono论文翻译(VINS-Mono: A Robust and Versatile MonocularVisual-Inertial State Estimator)

  返回  

luogu P4389 付公主的背包

2021/8/20 13:10:31 浏览:

https://www.luogu.com.cn/problem/P4389

首先知道对于一个体积为 v v v的物品,它的生成函数是 1 1 − x v \frac{1}{1-x^v} 1xv1
显然答案就是 F = ∏ i = 1 n 1 1 − x v i F= \prod_{i=1}^n\frac{1}{1-x^{v_i}} F=i=1n1xvi1

两边取对数 ln ⁡ F = ∑ i = 1 n ln ⁡ 1 1 − x v i \ln F=\sum_{i=1}^n\ln\frac{1}{1-x^{v_i}} lnF=i=1nln1xvi1

然后我们要知道 ln ⁡ 1 1 − x v = ∑ k = 1 1 k x v k \ln\frac{1}{1-x^v}=\sum_{k=1}\frac{1}{k}x^{vk} ln1xv1=k=1k1xvk
证明可以直接用复合函数求导再积分大力推
这样答案久很简单了,先把 v i v_i vi去个重,然后再把大小一样的丢到一起算,这样是调和级数的

之后把这个多项式exp一下就可以得到答案的生成函数了

code:



#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
#define N 8000005
using namespace std;
ll qpow(ll x, ll y){
    ll ret = 1;
    for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
    return ret;
}
int rev[N];
const int G = 3;
const int G_inv = qpow(G, mod - 2);
void ntt(ll *a, int n, int o){
    for(int i = 1; i < n; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i&1) * n >> 1);
    for(int i = 1; i < n; i ++) if(i < rev[i]) swap(a[i], a[rev[i]]);
    for(int len = 2; len <= n; len <<= 1){
        ll wn = qpow((o == 1)? G:G_inv, (mod - 1) / len);
        for(int j = 0; j < n; j += len){
            ll w0 = 1;
            for(int k = j; k < j + (len >> 1); k ++, w0 = w0 * wn % mod){
                int X = a[k], Y = w0 * a[k + (len >> 1)] % mod;
                a[k] = (X + Y) % mod;
                a[k + (len >> 1)] = (X - Y + mod) % mod;
            }
        }
    }
    int ninv = qpow(n, mod - 2); //printf("*%d %d\n", ninv, n);
    if(o == -1)
        for(int i = 0; i <= n; i ++) a[i] = a[i] * ninv % mod;
}
ll c[N];
void Inv(ll *a, ll *b, int sz){
    if(sz == 0) {b[0] = qpow(a[0], mod - 2); return;}
    Inv(a, b, sz / 2);
    int len = 1;
    for(; len <= sz + sz; len <<= 1);
    for(int i = 0; i <= sz; i ++) c[i] = a[i];
    for(int i = sz + 1; i <= len; i ++) c[i] = 0;
    ntt(c, len, 1), ntt(b, len, 1);
    for(int i = 0; i <= len; i ++) b[i] = (b[i] * 2 % mod - b[i] * b[i] % mod * c[i] % mod + mod) % mod;
    ntt(b, len, -1);
    for(int i = sz + 1; i <= len; i ++) b[i] = 0;
}
void qiudao(ll *a, int sz) {
    for(int i = 0; i < sz; i ++) a[i] = a[i + 1] * (i + 1) % mod;
    a[sz] = 0;
}
void jifen(ll *a, int sz) {
    for(int i = sz; i >= 1; i --) a[i] = a[i - 1] * qpow(i, mod - 2) % mod;
    a[0] = 0;
}
ll Ad[N], An[N];
void ln(ll *A, int n) {
    for(int i = 0; i <= n; i ++) Ad[i] = A[i];
    qiudao(Ad, n);
    Inv(A, An, n);
    int len = 1;
    for(; len <= n + n;) len <<= 1;
    ntt(Ad, len, 1), ntt(An, len, 1);
    for(int i = 0; i <= len; i ++) Ad[i] = Ad[i] * An[i] % mod;
    ntt(Ad, len, -1);
    jifen(Ad, n);
    for(int i = 0; i <= len; i ++) An[i] = 0;
    for(int i = 0; i <= n; i ++) A[i] = Ad[i];
}
ll fln[N];
void exp(ll *a, ll *b, int n) {
    if(n == 0) {b[0] = 1; return;}
    exp(a, b, n / 2);
    for(int i = 0; i <= n; i ++) fln[i] = b[i]; ln(fln, n);
    fln[0] = (fln[0] + 1) % mod;
    for(int i = 1; i <= n; i ++) fln[i] = (a[i] - fln[i] + mod ) % mod;
    int len = 1;
    for(; len <= n + n;) len <<= 1;
  //  for(int i = 0; i <= len; i ++) printf("%lld ", b[i]); printf("\n");
    //for(int i = 0; i <= len; i ++) printf("%lld ", fln[i]); printf("\n");
    
    ntt(b, len, 1), ntt(fln, len, 1);
    for(int i = 0; i <= len; i ++) b[i] = b[i] * fln[i] % mod;
    ntt(b, len, -1);
    //for(int i = 0; i <= len; i ++) printf("%lld ", b[i]); printf("\n\n");

    for(int i = 0; i <= len; i ++) fln[i] = 0;
}
ll a[N], b[N];
int cnt[N], inv[N];
int n, m;
void init(int n) {
    inv[0] = inv[1] = 1;
    for(int i = 2; i <= n; i ++) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
}
int main(){
    init(N - 5);
    scanf("%d%d", &n, &m);
    for(int i = 1, x; i <= n; i ++) {
        scanf("%d", &x);
        cnt[x] ++;
    }
    for(int i = 1; i <= m; i ++) if(cnt[i]) {
        for(int j = 1; j <= m / i; j ++)
            a[i * j] = (a[i * j] + 1ll * cnt[i] * inv[j] % mod) % mod;
    }
   // for(int i = 0; i <= m; i ++) printf("%lld ", a[i]); printf("\n");
    exp(a, b, m);
    for(int i = 1; i <= m; i ++) printf("%lld\n", b[i]);
    return 0;
}

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号