Educational Codeforces Round 81 (Rated for Div. 2) 题解

过了n天补的题解:D

AB就不用说了

C. Obtain The String

思路挺简单的,就是贪心,但是直接贪心的复杂度是O(|s|*|t|),会超时,所以需要用到序列自动机

虽然名字很高端但是就是个数组啦(不过我自己想不到就是了)

next[i][j]表示i之后第一次出现j字符的位置,用这个函数就可以把复杂度降到O(|t|)

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 100010;
char s[N], t[N];
bool flag[30];
int next[N][30];
int main() {
    int cs;
    scanf("%d", &cs);
    while (cs--) {
        scanf("%s", s);
        scanf("%s", t);
        int len1 = strlen(t);
        int len2 = strlen(s);
        int l = 0, cnt = 1;
        memset(next, 0xff, sizeof(next));
        for (int i = len2 - 1; i >= 0; i--) {
            for (int j = 0; j < 26; j++)
                next[i][j] = next[i + 1][j];
            next[i][s[i] - 'a'] = i;                 //递推式很简单
        }
        int pos = 0;
        for (int i = 0; i < len1; i++) {
            pos = next[pos][t[i] - 'a'] + 1;
            if (pos == 0) {
                cnt++;
                pos = next[0][t[i] - 'a'] + 1;
                if (pos == 0) {
                    cnt = -1;
                    break;
                }
            }
        }
        printf("%d\n", cnt);
    }
    return  0;
}

D.Same GCDs

如果知道了gcd(a, b) = gcd(a - b, b) (a > b)就是欧拉函数模板题,可惜不知道

gcd(a, m) = gcd(a + x, m) = k

gcd(a/k, m/k) = gcd(a/k + b, m/k) = 1

扫描二维码关注公众号,回复: 9064569 查看本文章

刚好就是phi[m/k]的值

#include <cstdio>
using namespace std;

long long gcd(long long a, long long b) {
    return (a % b == 0) ? b : gcd(b, a % b);
}

long long GetPhi(long long a) {
    long long res = a;
    for (long long i = 2; i * i <= a; i++) {
        if (a % i == 0) {
            res -= res / i;
            while (a % i == 0)
                a = a / i;
        }
    }
    if (a > 1)    res -= res / a;
    return res;
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        long long a, m;
        scanf("%lld %lld", &a, &m);
        long long k = gcd(a, m);
        long long ans = GetPhi(m / k);
        printf("%lld\n", ans);
    }
    return 0;
}
// gcd(a, m) = gcd(a + x, m) = k
// gcd(a/k, m/k) = gcd(a/k + b, m/k) = 1
// phi[m/k];

E.Permutation Separation

令set1 <= val,set2 =val 为若在pos的位置把序列分成两半,则val:=val + 1的时候[1, pos - 1]加上val对应的cost,[pos, n - 1]就减去这个cost,这个可以用线段树维护

然后有一个坑,把我卡在test 6了很久很久,就是val是从0开始,不是从1开始

#include <cstdio>
#include <algorithm>
using namespace std;
#define g(l, r) (l + r | l != r)
#define o g(l, r)
#define ls g(l, mid)
#define rs g(mid + 1, r)
const int N = 2 * 1e5 + 10;
typedef long long ll;
ll pos[N], p, w1, a[N];
ll pre[N], minn[N << 1], mark[N << 1];
int L, R;
void build(int l, int r) {
    if (l == r) {
        minn[o] = pre[l];
        return ;
    }
    int mid = l + r >> 1;
    build(l, mid); 
    build(mid + 1, r);
    minn[o] = min(minn[ls], minn[rs]);
}

inline void PushDown(int l, int r) {
    if (mark[o] != 0) {    
        int mid = l + r >> 1;
        mark[ls] += mark[o];
        mark[rs] += mark[o];
        minn[ls] = minn[ls] + mark[o];
        minn[rs] = minn[rs] + mark[o];
        mark[o] = 0;
    }
}

void update(int l, int r, int val) {
    if (L > R)    return ;
    if (L <= l && R >= r) {
        minn[o] += val;
        mark[o] += val;
        return ;
    }
    PushDown(l, r);
    int mid = l + r >> 1;
    if (L <= mid)    update(l, mid, val);
    if (R > mid)    update(mid + 1, r, val);
    minn[o] = min(minn[ls], minn[rs]);
}

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int k;
        scanf("%d", &k);
        pos[k] = i;
    }
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        pre[i] = pre[i - 1] + a[i];
    }
    build(1, n - 1);
    ll ans = minn[g(1, n - 1)];
    for (int i = 1; i <= n; i++) {
        L = pos[i], R = n - 1;
        update(1, n - 1, -a[pos[i]]);
        L = 1, R = pos[i] - 1;
        update(1, n - 1, a[pos[i]]);
        ans = min(ans, minn[g(1, n - 1)]);
    }
    printf("%lld", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cminus/p/12291878.html