不会,二分 / 三分,期望 dp + 高斯消元

# A. 记事本

不会。

30pts\text{30pts}:建图跑最短路。

60pts\text{60pts}:分讨模拟。

放个 60 分的代码吧。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
namespace IO{
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x * f;
    }
    template <typename T> inline void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;
const int N = 2010;
int n, q;
int a[N], pre[N], nxt[N];
int mn[N][20];
inline int qry(int l, int r){
    if(l >= r) return 1e9;
    int k = log2(r - l + 1);
    // cout << l << " " << r << " " << k << " " << r - (1 << k) + 1 << endl;
    return min(mn[l][k], mn[r - (1 << k) + 1][k]);
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    n = read();
    for(int i = 1; i <= n; ++i)
        a[i] = mn[i][0] = read(), pre[i] = nxt[i] = i;
    for(int i = 2; i <= n; ++i)
        if(a[i - 1] < a[i]) pre[i] = pre[i - 1];
    for(int i = n - 1; i >= 1; --i)
        if(a[i + 1] < a[i]) nxt[i] = nxt[i + 1];
    for(int j = 1; j <= 19; ++j)
        for(int i = 1; i + (1 << j) - 1 <= n; ++i)
            mn[i][j] = min(mn[i][j - 1], mn[i + (1 << (j - 1))][j - 1]);
    q = read();
    // for(int i = 44; i <= 58; ++i) cout << a[i] << " ";
    // cout << endl;
    while(q--){
        int r1 = read(), c1 = read(), r2 = read(), c2 = read(), cw = c1, ct = c1;
        // if(abs(r1 - r2) <= 10) cout << "???" << endl;
        int ans = 1e9;
        if(r1 < r2){
            c1 = min(c1, qry(r1, r2));
            // for(int i = r1; i <= r2; ++i) c1 = min(c1, a[i]);
            ans = r2 - r1 + min({abs(c1 - c2), c2 + (c1 != 0), a[r2] - c2 + (c1 != a[r2])});
            for(int i = r1; i <= r2; ++i){
                ct = min(ct, a[i]);
                int flag = (ct != a[i]);
                c1 = a[i];
                c1 = min(c1, qry(i + 1, r2));
                // for(int j = i + 1; j <= r2; ++j) c1 = min(c1, a[j]);
                ans = min(ans, r2 - r1 + flag + abs(c1 - c2));
            }
            for(int i = r2 + 1; i <= n; ++i){
                ct = min(ct, a[i]);
                int flag = (ct != a[i]);
                c1 = a[i];
                c1 = min(c1, qry(r2, i - 1));
                // for(int j = i - 1; j >= r2; --j) c1 = min(c1, a[j]);
                ans = min(ans, i - r1 + i - r2 + abs(c1 - c2) + flag);
            }
            ct = cw;
            for(int i = r1 - 1; i >= 1; --i){
                ct = min(ct, a[i]);
                int flag = (ct != a[i]);
                c1 = a[i];
                c1 = min(c1, qry(i + 1, r2));
                // for(int j = i + 1; j <= r2; ++j) c1 = min(c1, a[j]);
                ans = min(ans, r2 - i + r1 - i + abs(c1 - c2) + flag);
            }
            write(ans), puts("");
        }else{
            c1 = min(c1, qry(r2, r1));
            // for(int i = r2; i <= r1; ++i) c1 = min(c1, a[i]);
            ans = r1 - r2 + min({abs(c1 - c2), c2 + (c1 != 0), a[r2] - c2 + (c1 != a[r2])});
            c1 = cw;
            for(int i = r1; i >= r2; --i){
                ct = min(ct, a[i]);
                int flag = (ct != a[i]);
                c1 = a[i];
                c1 = min(c1, qry(r2, i - 1));
                // for(int j = i - 1; j >= r2; --j) c1 = min(c1, a[j]);
                ans = min(ans, r1 - r2 + flag + abs(c1 - c2));
            }
            for(int i = r2 - 1; i >= 1; --i){
                ct = min(ct, a[i]);
                int flag = (ct != a[i]);
                c1 = a[i];
                c1 = min(c1, qry(i + 1, r2));
                // for(int j = i + 1; j <= r2; ++j) c1 = min(c1, a[j]);
                ans = min(ans, r1 - i + r2 - i + abs(c1 - c2) + flag);
            }
            ct = cw;
            for(int i = r1 + 1; i <= n; ++i){
                ct = min(ct, a[i]);
                int flag = (ct != a[i]);
                c1 = a[i];
                c1 = min(c1, qry(r2, i - 1));
                // for(int j = i - 1; j >= r2; --j) c1 = min(c1, a[j]);
                ans = min(ans, i - r1 + i - r2 + abs(c1 - c2) + flag);
            }
            write(ans), puts("");
        }
    }
    return 0;
}

# B. 子集

枚举中位数,二分选数个数,手动计算价值。

#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
namespace IO{
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x * f;
    }
    template <typename T> inline void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;
const int N = 2e5 + 10;
int n;
int a[N], s[N];
inline double calc(int x, int mid){
    int sum = s[x] - s[x - mid - 1] + s[n] - s[n - mid];
    return 1.0 * sum / (mid + mid + 1) - a[x];
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    n = read();
    for(int i = 1; i <= n; ++i) a[i] = read();
    sort(a + 1, a + 1 + n);
    for(int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i];
    double ans = 0;
    if(n <= 2000){
        for(int i = 1; i <= n; ++i){
            int l = i - 1, r = n, sum = a[i], cnt = 1;
            while(l >= 1 && r > i){
                sum += a[l] + a[r];
                l--, r--, cnt += 2;
                ans = max(ans, 1.0 * sum / cnt - a[i]);
            }
        }
    }else{
        for(int i = 1; i <= n; ++i){
            int l = 0, r = min(i - 1, n - i);
            while(l <= r){
                int mid = (l + r) >> 1;
                // cout << l << " " << r << " " << midl << " " << midr << endl;
                if(calc(i, mid) > calc(i, mid - 1)) l = mid + 1;
                else r = mid - 1;
            }
            ans = max(ans, calc(i, r));
            // ans = max({ans, calc(i, l), calc(i, r)});
        }
    }
    printf("%.5lf\n", ans);
    return 0;
}

# C. 子串

先建出 AC 自动机,设 fif_i 表示到达 AC 自动机上 ii 点时期望再加上多少个点结束。

那么有 fendi=0f_{end_i} = 0

yy 是 AC 自动机上 xx 的子节点,有转移:

fx=126yson(x)fy+1f_x = \frac {1}{26}\sum_{y \in son(x)} f_y + 1

根据这个式子建出方程组,然后高斯消元即可。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
namespace IO{
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x * f;
    }
    template <typename T> inline void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;
const int N = 200;
const int mod = 1e9 + 7;
int T, n, inv26;
char s[N];
inline int add(int x) {return x >= mod ? x - mod : x;}
inline int sub(int x) {return x < 0 ? x + mod : x;}
inline int mul(int x, int y) {return 1ll * x * y % mod;}
inline int qpow(int a, int b){
    int res = 1;
    while(b){
        if(b & 1) res = mul(res, a);
        a = mul(a, a), b >>= 1;
    }
    return res;
}
int ch[N][26], tot, End[N];
int fail[N];
inline void insert(char *s){
    int len = strlen(s), now = 0;
    for(int i = 0; i < len; ++i){
        int c = s[i] - 'a';
        if(!ch[now][c]) ch[now][c] = ++tot;
        now = ch[now][c];
    }
    End[now] = 1;
}
inline void build(){
    queue <int> q;
    for(int i = 0; i < 26; ++i)
        if(ch[0][i]) q.push(ch[0][i]);
    while(!q.empty()){
        int x = q.front(); q.pop();
        for(int i = 0; i < 26; ++i){
            if(ch[x][i]) fail[ch[x][i]] = ch[fail[x]][i], q.push(ch[x][i]);
            else ch[x][i] = ch[fail[x]][i];
        }
    }
}
int a[N][N];
inline void Gauss(int n){
    for(int i = 0; i <= n; ++i){
        for(int j = i + 1; j <= n && a[i][i] == 0; ++j)
            if(a[j][i]) swap(a[i], a[j]);
        int inv = qpow(a[i][i], mod - 2);
        for(int j = i + 1; j <= n; ++j)
            for(int k = n + 1; k >= i; --k)
                a[j][k] = sub(a[j][k] - mul(a[i][k], mul(a[j][i], inv)));
    }
    for(int i = n; i >= 0; --i){
        for(int j = i + 1; j <= n; ++j)
            a[i][n + 1] = sub(a[i][n + 1] - mul(a[i][j], a[j][n + 1]));
        a[i][n + 1] = mul(a[i][n + 1], qpow(a[i][i], mod - 2));
    }
}
inline void solve(){
    tot = 0;
    memset(a, 0, sizeof(a));
    memset(ch, 0, sizeof(ch));
    memset(End, 0, sizeof(End));
    memset(fail, 0, sizeof(fail));
    n = read();
    for(int i = 1; i <= n; ++i)
        scanf("%s", s), insert(s);
    build();
    for(int i = 0; i <= tot; ++i){
        a[i][i] = 1;
        if(End[i]) continue;
        a[i][tot + 1] = 1;
        for(int j = 0; j < 26; ++j)
            a[i][ch[i][j]] = sub(a[i][ch[i][j]] - inv26);
    }
    Gauss(tot);
    write(a[0][tot + 1]), puts("");
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    T = read(), inv26 = qpow(26, mod - 2);
    while(T--) solve();
    return 0;
}
更新于 阅读次数