hdu-6472 艺术台阶(微积分+多项式维护)

传送门

题意:

实际上就是求\(\sum^{a[1]}_{i=0}\frac{1}{a[1]}\sum^{a[2]}_{j=i}\frac{1}{a[2]}\sum^{a[3]}_{k=j}\frac{1}{a[3]}\cdots(a[1]<=a[2]<=a[3]\cdots)\)

解题思路:

题目给我们的a[i]并不保证是非递减的,比如一个1 4 2的序列,所以实际上的积分是\(\frac{1}{1*4*2}\sum^{1}_{i=0}\sum^{2}_{j=i}\sum^{2}_{k=j}\)
那么我们假设处理好的每个积分上限为\(b[i]\)
以三项为例
那么把系数往前提就有
\(\frac{1}{\prod^{n}_{i=1}a[i]}\sum^{b[1]}_{i=0}\sum^{b[2]}_{j=i}\sum^{b[3]}_{k=j}\)
我们从最后一个积分往前积,一开始要维护的多项式只有一个1,\(1dk=k\),已知上下限做定积分就有
\(\frac{1}{\prod^{n}_{i=1}a[i]}\sum^{b[1]}_{i=0}\sum^{b[2]}_{j=i}(b[3]-j)\)
同理\((b[3]-j)dj=b[3]j-\frac{j^2}{2}\)
\(\frac{1}{\prod^{n}_{i=1}a[i]}\sum^{b[1]}_{i=0}b[3]i-\frac{i^2}{2}\)
这就差不多了,为了避免浮点数,我分别维护了多项式的分子和分母,显然多项式每次只要乘以阶乘所有系数就能变成整数,只要分子分母同乘以阶乘即可,但是阶乘在预处理的过程中模过,导致直接除的时候不一定被整除,所以乘以阶乘的逆元就差不多了

#include <bits/stdc++.h>
using namespace std;
/*    freopen("k.in", "r", stdin);
    freopen("k.out", "w", stdout); */
// clock_t c1 = clock();
// std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef pair<ll, ll> PLL;
typedef vector<int, int> VII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e5 + 7;
const ll MAXM = 2e6 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
ll quick_pow(ll a, ll b)
{
    ll ans = 1;
    while (b)
    {
        if (b & 1)
            ans = (1LL * ans * a) % MOD;
        a = (1LL * a * a) % MOD;
        b >>= 1;
    }
    return ans;
}
ll mp[3005];
ll a[3005];
ll b[3005];
ll fac[3005];
ll pre[3005];
int main()
{
    int n;
    int t;
    scanf("%d", &t);
    fac[0] = fac[1] = 1;
    for (int i = 1; i <= 2005; i++)
    {
        (fac[i] = fac[i - 1] * i) %= MOD;
        pre[i] = quick_pow(i, MOD - 2);
    }
    while (t--)
    {
        memset(mp, 0, sizeof(mp));
        scanf("%d", &n);
        ll div = 1;
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &a[i]);
            b[i] = a[i];
            div *= a[i];
            div %= MOD;
        }
        for (int i = n; i >= 2; i--)
        {
            if (b[i - 1] > b[i])
                b[i - 1] = b[i];
        }
        ll now = 2;
        mp[1] = 1;
        for (int i = n; i >= 2; i--)
        {
            ll temp = 0;
            for (int j = 0; j <= now - 1; j++)
            {
                (temp += (mp[j] * quick_pow(b[i], j)) % MOD) %= MOD;
                mp[j] = -mp[j];
            }
            (mp[0] += temp) %= MOD;
            for (int j = now; j >= 1; j--)
            {
                mp[j] = ((fac[now] * pre[j] % MOD) * mp[j - 1]) % MOD;
                mp[j] %= MOD;
            }
            mp[0] = 0;
            (div *= fac[now]) %= MOD;
            now++;
        }
        ll son = 0;
        for (int i = 0; i <= n; i++)
        {
            son += ((mp[i] * quick_pow(b[1], i)) % MOD);
            son %= MOD;
        }
        ll inv = quick_pow(div, MOD - 2);
        printf("%lld\n", ((son * inv % MOD) + MOD) % MOD);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/graytido/p/12296710.html