zoukankan      html  css  js  c++  java
  • AtCoder ABC208 F

    写在前面

    昨天 ABC 的 F 题,结论推出来了,猜到是拉格朗日,奈何我只会板子,不会分析次数;

    赛后知道正解后感觉大受震撼。我还是太 naive 了 /kk

    前置知识

    • 组合数学

    • 拉格朗日插值法。

    Description

    原题地址

    给你 (n, m, k),定义 (f(n, m)) 为:

    [displaystyle f(n, m) = egin{cases} 0 & (n = 0) ewline n^K & (n gt 0, m = 0) ewline f(n-1, m) + f(n, m-1) & (n gt 0, m gt 0) end{cases} ]

    (f(n,m) mod 10^9+7)

    数据范围:

    (0 le n le 10^{18})

    (0 le m le 30)

    (1 le k le 2.5 imes 10^{6})

    Solution

    先对第一个样例搞一下。

    我们用下面这个表格来算一下 (f(3,4)) 最终递归调用 (f(i,0)) 多少次

    [egin{array}{c|lcr} & m = 0 & m = 1 & m = 2 & m = 3 & m = 4 \ hline n = 0 & 20 & 20 & 10 & 4 & 1\ n = 1 & 10 & 10 & 6 & 3 & 1\ n = 2 & 4 & 4 & 3 & 2 & 1\ n = 3 & 1 & 1 & 1 & 1 & 1 end{array} ]

    结合 (f(n, m) = f(n-1,m) + f(n, m-1) (n > 0, m > 0)) 的递归式

    发现这个玩意很像平面上 ((0,0))((n,m)) 的方案数。

    而我们求的 (f(i,0)) 就对应着 ((i, 1))((n, m)) 的方案数。

    根据组合数学,可以算出 (f(i,0)) 调用了 (C_{n+m-i-1}^{m-1})

    又因为 (f(i,0) = i^k)

    然后我们就能够用一个式子表示出答案:

    [sum_{i = 0}^{n} inom{n+m-i-1}{m-1} i^k ]

    根据 @GuidingStar 的说法

    前缀和是 (1) 次, (inom{n+m-i-1}{m-1})(m-1) 次,(i^k)(k) 次, 一共 (k+m) 次。

    吾以为 之所以 (inom{n+m-i-1}{m-1})(m-1) 次,是因为这个式子约分之后分子与 (i) 相关的一共有 (m-1) 项,至于下面的 ((m-1)!)(i) 无关。

    我们设 (F(n) = sum_{i = 0}^{n} inom{n+m-i-1}{m-1} i^k)

    这是一个 (k+m) 次多项式,我们只要找到 (k+m+1) 个点就能确定他的式子。

    这里我们取 (x = 0 sim k + m) 这一段连续的区间,用暴力刷表的方法求出 ((x, F(x)))

    然后利用拉格朗日插值法求解即可。

    用到 (x) 取值连续时的优化,如果不会可以参考这篇博客

    总复杂度为 (O((k+m) log k)),可以通过。

    Code

    /*
    Work by: Suzt_ilymics
    Problem: 
    Knowledge: 拉格朗日插值法
    Time: O((k+m)log mod)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define int long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 5e6+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    int n, m, k, Ans = 0;
    int S[MAXN], fac[MAXN], inv[MAXN], pre[MAXN], suf[MAXN];
    int ans[MAXN];
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    int Pow(int x, int p, int mod) {
        int res = 1;
        while(p) {
            if(p & 1) res = res * x % mod;
            x = x * x % mod;
            p >>= 1;
        }
        return res;
    }
    
    signed main()
    {
        n = read(), m  =read(), k = read();
        if(!m) {
            printf("%lld
    ", Pow(n % mod, k, mod));
            return 0;
        }
        if(!n) {
            printf("0
    ");
            return 0;
        }
        ans[0] = 0;
        for(int i = 1; i <= k + m; ++i) S[i] = Pow(i, k, mod);
        for(int i = 1; i <= m; ++i) {
            for(int j = 1; j <= k + m; ++j) {
                ans[j] = (ans[j - 1] + S[j]) % mod;
            }
            for(int j = 1; j <= k + m; ++j) {
                S[j] = ans[j];
            }
        }
        if(n <= k + m) {
            printf("%lld
    ", ans[n]);
            return 0;
        }
    //    for(int i = 1; i <= k + 2; ++i) inv[i] = Pow(fac[i], mod - 2, mod);
        pre[0] = n % mod, suf[k + m + 1] = 1, fac[0] = 1;
        for(int i = 1; i <= k + m; ++i) pre[i] = pre[i - 1] * ((n - i) % mod) % mod;
        for(int i = k + m; i >= 0; --i) suf[i] = suf[i + 1] * ((n - i) % mod) % mod;
        for(int i = 1; i <= k + m; ++i) fac[i] = fac[i - 1] * i % mod;
        for(int i = 0; i <= k + m; ++i) {
            int a = (i == 0 ? 1 : pre[i - 1]) * suf[i + 1] % mod;
            int b = fac[i] * ((k + m - i) & 1 ? -1 : 1) * fac[k + m - i] % mod;
            Ans = Ans + S[i] * a % mod * Pow(b, mod - 2, mod) % mod;
            Ans %= mod;
        }
        printf("%lld
    ", (Ans + mod) % mod);
        return 0;
    }
    
  • 相关阅读:
    hdu 3342 Legal or Not 拓排序
    hdu 1596 find the safest road Dijkstra
    hdu 1874 畅通工程续 Dijkstra
    poj 2676 sudoku dfs
    poj 2251 BFS
    poj Prime Path BFS
    poj 3278 BFS
    poj 2387 Dijkstra 模板
    poj 3083 DFS 和BFS
    poj 1062 昂贵的聘礼 dijkstra
  • 原文地址:https://www.cnblogs.com/Silymtics/p/14972735.html
Copyright © 2011-2022 走看看