省选测试39

A 老洪的遍历

题目大意 : 从一个点走到另一个点会有一定贡献,问按要求走完一些点再回到原点能拿到的最大收益

  • 给了a[i],s是a的前缀和,从i点到j点收益是 (frac{(a_i-a_j)s_is_j}{2a_ia_j}) ,拆一下就是 (frac{1}{2}(s_ifrac{s_j}{a_j}-s_jfrac{s_i}{a_i}))

  • 发现如果设第i个点的向量是 ((s_i,frac{s_i}{a_i})) , 那就是两个点的向量点乘起来除以2,就是和原点组成三角形的面积

  • 由于要回到原点,最后会形成一个封闭图形,最后让面积最大,然后就是维护凸包,计算面积即可

Code

Show Code
#include <cstdio>
#include <algorithm>

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;
}

struct Node {
    double x, y;
}a[N], stk[N];

Node operator - (const Node &a, const Node &b) {
    return (Node) {a.x - b.x, a.y - b.y};
}

double operator * (const Node &a, const Node &b) {
    return a.x * b.y - a.y * b.x;
}

bool operator < (const Node &a, const Node &b) {
    return a.x != b.x ? a.x < b.x : a.y < b.y;
}

int n, s, tp, k;
double ans;

int main() {
    freopen("visit.in", "r", stdin);
    freopen("visit.out", "w", stdout);
    n = read();
    for (int i = 1; i <= n; ++i) {
        int x = read(); s += x;
        a[i] = (Node) {1.0 * s, 1.0 * s / x};
    }
    sort(a + 1, a + n + 1);
    stk[k = ++tp] = a[1];
    for (int i = 2; i <= n; ++i) {
        while (tp > k && (stk[tp] - stk[tp-1]) * (a[i] - stk[tp-1]) >= 0) tp--;
        stk[++tp] = a[i];
    }
    k = tp;
    for (int i = n - 1; i >= 1; --i) {
        while (tp > k && (stk[tp] - stk[tp-1]) * (a[i] - stk[tp-1]) >= 0) tp--;
        stk[++tp] = a[i];
    }
    for (int i = 1; i < tp; ++i)
        ans += stk[i] * stk[i+1];
    printf("%.5lf
", -ans / 2);
    return 0;
}

B 老洪的神秘操作

题目大意 : 给一个序列,每次可以区间加一个数,问让每个数在模7的意义下与0同余所需的最少操作次数

  • 看到区间加可以转换成差分,最后就是让差分数组为零,稍微想想就会发现,最后求的其实是把n个数分组,让和为0的组数尽量多

  • 0的肯定自己一组,1+6,2+5,3+4都是可以直接匹配起来的,所以最后最多剩下3个数

  • 设f[i][j][k][l]为第一个数选了i个,第二个数选了j个,第三个数选了k个,最后一组和为l,可以分出的最多组数

  • 转移的时候枚举三个数放的是哪个。空间开不下,第一维滚动压掉就行

Code

Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 501;

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, s[9], ans, f[N][N][9], g[N][N][9], a[9], cnt, mx;

int main() {
    freopen("secret.in", "r", stdin);
    freopen("secret.out", "w", stdout);
    int x = 0; ans = n = read();
    for (int i = 1; i <= n; ++i) {
        int y = read();
        s[(y-x+7)%7]++; x = y;
    }
    ans -= s[0]; s[0] = 0;
    x = min(s[1], s[6]); ans -= x; s[1] -= x; s[6] -= x;
    x = min(s[2], s[5]); ans -= x; s[2] -= x; s[5] -= x;
    x = min(s[3], s[4]); ans -= x; s[3] -= x; s[4] -= x;
    for (int i = 1; i <= 6; ++i) 
        if (s[i]) a[++cnt] = i;
    memset(g, 0xcf, sizeof(g)); g[0][0][0] = 0;
    for (int i = 0; i <= s[a[1]]; ++i) {
        memcpy(f, g, sizeof(g));
        memset(g, 0xcf, sizeof(g));
        for (int j = 0; j <= s[a[2]]; ++j) {
            for (int k = 0; k <= s[a[3]]; ++k) {
                for (int l = 0; l <= 6; ++l) {
                    int x = (l + a[1]) % 7;
                    g[j][k][x] = max(g[j][k][x], f[j][k][l] + !x);
                    x = (l + a[2]) % 7;
                    f[j+1][k][x] = max(f[j+1][k][x], f[j][k][l] + !x);
                    x = (l + a[3]) % 7;
                    f[j][k+1][x] = max(f[j][k+1][x], f[j][k][l] + !x);
                }
            }
        }
    }
    for (int i = 0; i <= 6; ++i)
        mx = max(mx, f[s[a[2]]][s[a[3]]][i]);
    printf("%d
", ans - mx);
    return 0;
}

C 老洪的数组

题目大意 : 二维数组,第一行给定,其他的是上面的加左面的,动态修改第一行的某个数,询问一个20行以内的数是什么

  • 把询问分成k组,每一组开始的时候把所有的数预处理出来,然后考虑这组询问里的修改造成的影响,时间复杂度 (O(sqrt n))

Code

Show Code
#include <cmath>
#include <cstdio>

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

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, m, sz, f[21][N], fac[N], inv[N], a[N], b[N], cnt;

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;
}

void Init(int n) {
    fac[0] = 1;
    for (int i = 1; i <= n; ++i)
        fac[i] = 1ll * fac[i-1] * i % M;
    inv[n] = Pow(fac[n], M - 2);
    for (int i = n; i >= 1; --i)
        inv[i-1] = 1ll * inv[i] * i % M;
}

int C(int n, int m) {
    return 1ll * fac[n] * inv[m] % M * inv[n-m] % M;
}

int main() {
    freopen("array.in", "r", stdin);
    freopen("array.out", "w", stdout);
    n = read(); m = read();
    sz = sqrt(80 * n); Init(n + 20);
    for (int i = 1; i <= n; ++i)
        f[0][i] = read(), a[i] = -1;
    for (int t = 1; t <= m; ++t) {
        if (t % sz == 1) {
            for (int i = 1; i <= cnt; ++i)
                f[0][b[i]] = a[b[i]], a[b[i]] = -1;
            cnt = 0;
            for (int i = 1; i <= 20; ++i)
                for (int j = 1; j <= n; ++j)
                    if ((f[i][j] = f[i-1][j] + f[i][j-1]) >= M) f[i][j] -= M;
        }
        int od = read(), x = read(), y = read();
        if (od == 2) {
            int ans = f[x][y];
            for (int i = 1; i <= cnt; ++i)
                if (x && y >= b[i]) ans = (ans + 1ll * C(x - 1 + y - b[i], x - 1) * (a[b[i]] - f[0][b[i]] + M)) % M;
            printf("%d
", ans);
        }
        else if (a[x] != -1) a[x] = y;
        else ++cnt, b[cnt] = x, a[x] = y;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shawk/p/14559294.html