zoukankan      html  css  js  c++  java
  • BZOJ2655: calc(dp 拉格朗日插值)

    题意

    题目链接

    Sol

    首先不难想到一个dp

    (f[i][j])表示选了(i)严格递增的数最大的数为(j)的方案数

    转移的时候判断一下最后一个位置是否是(j)

    [f[i][j] = f[i][j - 1] + f[i - 1][j - 1] * j ]

    for(int i = 0; i <= A; i++) f[0][i] = 1;
    for(int i = 1; i <= N; i++)
        for(int j = 1; j <= A; j++) 
            f[i][j] = add(f[i][j - 1], mul(f[i - 1][j - 1], j));
    cout << mul(f[N][A], fac[N]);
    

    发现还是不好搞,把转移拆开

    (f[i][j] = sum_{k = 0}^{j - 1} f[i - 1][k] * (k + 1))

    这个转移就非常有意思了

    我们如果把(i)看成列,(k)看成行,那么转移的时候实际上就是先对第(k)行乘上一个系数(k),然后再求和

    如果我们把第(i - 1)列看成一个(t)次多项式,显然第(i)列是一个(t+2)次多项式(求和算一次,乘系数算一次)

    这样的话第(i)列就是一个最高(2i+1)次多项式

    插一插就好了

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 10001;
    int A, N, Lim, mod, f[501][MAXN], fac[MAXN], y[MAXN];
    int add(int x, int y) {
        if(x + y < 0) return x + y + mod;
        return x + y >= mod ? x + y - mod : x + y;
    }
    void add2(int &x, int y) {
        if(x + y < 0) x = (x + y + mod);
        else x = (x + y >= mod ? x + y - mod : x + y);
    }
    int mul(int x, int y) {
        return 1ll * x * y % mod;
    }
    int fp(int a, int p) {
        int base = 1;
        while(p) {
            if(p & 1) base = mul(base, a);
            a = mul(a, a); p >>= 1;
        }
        return base;
    }
    int Large(int *y, int k) {
        static int x[MAXN], ans = 0;
        for(int i = 1; i <= Lim; i++) x[i] = i;
        for(int i = 0; i <= Lim; i++) {
            int up = y[i], down = 1;
            for(int j = 0; j <= Lim; j++) {
                if(i == j) continue;
                up = mul(up, add(k, -x[j]));
                down = mul(down, add(x[i], -x[j]));
            }
            add2(ans, mul(up, fp(down, mod - 2)));
        }
        return ans;
    }
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("a.in", "r", stdin);
       // freopen("a.out", "w", stdout);
    #endif
        cin >> A >> N >> mod; Lim = 2 * N + 1;
        fac[0] = 1; for(int i = 1; i <= N; i++) fac[i] = mul(i, fac[i - 1]);
        for(int i = 0; i <= Lim; i++) f[0][i] = 1;
        for(int i = 1; i <= N; i++) {
            for(int j = 1; j <= Lim; j++) {
                f[i][j] = add(f[i][j - 1], mul(f[i - 1][j - 1], j));
            }
        }
        for(int i = 0; i <= Lim; i++) y[i] = f[N][i];
        cout << mul(Large(y, A), fac[N]);
        return 0;
    }
    
    
  • 相关阅读:
    bzoj千题计划108:bzoj1018: [SHOI2008]堵塞的交通traffic
    bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix
    2017 清北济南考前刷题Day 7 morning
    2017 清北济南考前刷题Day 7 afternoon
    2017 清北济南考前刷题Day 6 afternoon
    2017 清北济南考前刷题Day 6 morning
    2017 清北济南考前刷题Day 5 afternoon
    怎么样在线创建索引或者重构索引
    10g RAC常用开启关闭命令 – SRVCTL用法
    安装Oracle 10g RAC是否需要安装HACMP
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10062445.html
Copyright © 2011-2022 走看看