省选测试28

A Inverse

题目大意 : 给一个排列,翻转k次,问最终逆序对个数的期望值

  • 定义f[k][i][j]为翻转了k次后a[i]<a[j]的概率,每次可以枚举翻转区间进行转移,复杂度 (O(n^4k))

  • 对于一个区间l,r

    • 如果 (lleq ileq r<j),改变 i 的位置,从 f[k-1][l+r-i][j] 转移来

    • 如果 (i<lleq jleq r), 改变 j 的位置,从 f[k-1][i][l+r-j] 转移来

    • 如果 (lleq i<jleq r), i,j 位置都改变,从 f[k-1][l+r-i][l+r-j] 转移来

  • 然后在用两个前缀和分别优化这3种转移就好了

Code

Show Code
#include <cstdio>
#define Mod(x) ({ int xx = x; xx > M ? xx - M : xx; })

using namespace std;
const int N = 505, M = 1e9 + 7;

int n, k, a[N], f[N][N], s1[N][N], s2[N][N], s3[N][N], s4[N][N], s5[N][N], s6[N][N], ans, p = 1;

int Pow(int a, int k, int ans = 1) {
    for (; k; k >>= 1, a = 1ll * a * a % M)
        if (k & 1) ans = 1ll * ans * a % M;
    return ans;
}

int Cal(int x) {
    return x * (x + 1) / 2;
}

int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            f[i][j] = a[i] > a[j];
    while (k--) {
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                s1[i][j] = Mod(s1[i][j-1] + f[i][j]);
                s2[i][j] = Mod(s2[i][j-1] + s1[i][j]);
                s3[i][j] = Mod(s3[i-1][j] + f[i][j]);
                s4[i][j] = Mod(s4[i-1][j] + s3[i][j]);
                s5[i][j] = Mod(s5[i-1][j-1] + f[i][j]);
                s6[i][j] = Mod(s6[i-1][j-1] + s5[i][j]);
            }
        }
        for (int i = 1; i <= n; ++i)
            for (int j = i + 1; j <= n; ++j)
                f[i][j] = (f[i][j] * (1ll * Cal(i-1) + Cal(j-i-1) + Cal(n-j)) + s2[i][n] + s2[i][i-1] - s2[i][n+i-j] + M - s2[i][j-1] + M + s4[j-1][j] - s4[j-i-1][j] + M - s4[i-1][j] + M + s6[n][n+i-j] - s6[n-i][n-j] + M - s6[j-1][i-1] + M) % M;
        p = 1ll * p * Cal(n) % M;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j < i; ++j)
                f[i][j] = Mod(p - f[j][i] + M);
    }
    for (int i = 1; i <= n; ++i)
        for (int j = i + 1; j <= n; ++j)
            if ((ans += f[i][j]) >= M) ans -= M;
    printf("%lld
", 1ll * ans * Pow(p, M - 2) % M);
    return 0;
}

B Subsequence

题目大意 : 定义一个长度为k的序列B的权值是 (sum_{i-1}^{k}i imes B_i),给一个长度为n的序列问长度分别为1到n的子序列最大权值

  • n2的dp很好写,f[i][j]表示前i个数选j个的最大权值,转移的话就是f[i][j]=max(f[i-1][j],f[i-1][j-1]+a[i]*j)

  • 然后发现一个性质就是如果对于一个j来说,f[i-1][j-1]+a[i]*j > f[i-1][j],那么更大的j也会满足,就是说有一个更新了,后面的都要更新

  • 然后设g[i][j]=g[i][j]-g[i][j-1],假设第1个更新的位置是j,那么g[i]和g[i-1]的区别就是g[i][j]变成a[i]*j,后面的g[i][k]变成g[i-1][k-1]+a[i]

  • 也就是进行了插入一个a[i]*j,然后对后面的数区间加a[i],可以用splay来维护

Code

Show Code
#include <cstdio>
#define Get(x) (t[fa[x]][1] == x)

using namespace std;
const int N = 1e5 + 5;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
    return x * f;
}

int n, t[N][2], fa[N], sz[N], rt, stk[N], tp;
long long tag[N], w[N], ans;

void Pushup(int x) {
    sz[x] = sz[t[x][0]] + sz[t[x][1]] + 1;
}

void Rotate(int x) {
    int y = fa[x], z = fa[y], k = Get(x), B = t[x][k^1];
    t[z][Get(y)] = x; fa[x] = z;
    t[x][k^1] = y; fa[y] = x;
    t[y][k] = B; fa[B] = y;
    Pushup(y); Pushup(x);
}

void Uptate(int x, long long val) {
    w[x] += val; tag[x] += val;
}

void Pushdown(int x) {
    if (!tag[x]) return;
    Uptate(t[x][0], tag[x]);
    Uptate(t[x][1], tag[x]);
    tag[x] = 0;
}

void Splay(int x, int to = 0) {
    for (int y = x; y != to; y = fa[y]) stk[++tp] = y;
    while (tp) Pushdown(stk[tp--]);
    while (fa[x] != to) {
        int y = fa[x];
        if (fa[y] != to) Get(x) != Get(y) ? Rotate(x) : Rotate(y);
        Rotate(x);
    }
    if (!to) rt = x;
}

void Dfs(int x) {
    if (!x) return;
    Pushdown(x);
    Dfs(t[x][0]);
    printf("%lld ", ans += w[x]);
    Dfs(t[x][1]);
}

int main() {
    n = read(); w[1] = read(); sz[1] = rt = 1;
    for (int i = 2; i <= n; ++i) {
        int val = read(), x = rt, sum = 1, lt, k;
        while (x) {
            Pushdown(lt = x);
            if (w[x] > 1ll * val * (sum + sz[t[x][0]]))
                sum += sz[t[x][0]] + 1, k = 1;
            else k = 0;
            x = t[x][k];
        }
        t[lt][k] = i; fa[i] = lt; w[i] = 1ll * val * sum;
        Splay(i); Uptate(t[i][1], val);
    }
    Dfs(rt);
    return 0;
}

C Convex (Unaccepted)

题目大意 :

Code

Show Code
原文地址:https://www.cnblogs.com/shawk/p/14436514.html