2019 Multi-University Training Contest 5

我不仅又变菜了,还学会了演戏

1002 - three arrays

分析:每次贪心的取两个集合中异或值最小的一个pair,那么首先可以确定使用字典树来解决。比较容易想到用两颗字典树来维护,问题在于如何取最小值,因为不能确定两棵树同时走0还是同时走1。

其实只需要一起走就可以了,因为同一个节点的0和1是相互不影响的,那么从0向下递归,与从1向下递归,他们的结果也是不相互影响的,所以只需要把整棵树跑完最后在排个序就可以了。

那么最后的做法就是同步的跑两棵树,优先跑00和11,再跑01和10。

#include "bits/stdc++.h"

using namespace std;
struct node {
    int nxt[2], num;
} a[100004 * 32], b[100004 * 32];
int cnt1, cnt2;
int ans[100004];
int cnt;

void init() {
    cnt1 = cnt2 = cnt = 0;
    a[0].nxt[0] = a[0].nxt[1] = b[0].nxt[0] = b[0].nxt[1] = -1;
    a[0].num = b[0].num = 0;
}

void ins(node t[], char s[], int root, int &cnt) {
    int len = strlen(s);
    for (int i = 0; i < len; ++i) {
        if (t[root].nxt[s[i] - '0'] == -1) {
            t[root].nxt[s[i] - '0'] = ++cnt;
            root = cnt;
            t[root] = {{-1, -1}, 0};
        } else root = t[root].nxt[s[i] - '0'];
        t[root].num++;
    }
}

int qu(int rt1, int rt2, int w, int base) {
    bool ok = 1;
    int res = 0;
    while ((~a[rt1].nxt[0]) && (~b[rt2].nxt[0])) {
        int temp = qu(a[rt1].nxt[0], b[rt2].nxt[0], w, base >> 1);
        res += temp;
        a[rt1].num -= temp;
        b[rt2].num -= temp;
        int nx1 = a[rt1].nxt[0], nx2 = b[rt2].nxt[0];
        if (a[nx1].num == 0)
            a[rt1].nxt[0] = -1;
        if (b[nx2].num == 0)
            b[rt2].nxt[0] = -1;
        ok = 0;
    }
    while ((~a[rt1].nxt[1]) && (~b[rt2].nxt[1])) {
        int temp = qu(a[rt1].nxt[1], b[rt2].nxt[1], w, base >> 1);
        res += temp;
        a[rt1].num -= temp;
        b[rt2].num -= temp;
        int nx1 = a[rt1].nxt[1], nx2 = b[rt2].nxt[1];
        if (a[nx1].num == 0)
            a[rt1].nxt[1] = -1;
        if (b[nx2].num == 0)
            b[rt2].nxt[1] = -1;
        ok = 0;
    }
    while ((~a[rt1].nxt[0]) && (~b[rt2].nxt[1])) {
        int temp = qu(a[rt1].nxt[0], b[rt2].nxt[1], w + base, base >> 1);
        res += temp;
        a[rt1].num -= temp;
        b[rt2].num -= temp;
        int nx1 = a[rt1].nxt[0], nx2 = b[rt2].nxt[1];
        if (a[nx1].num == 0)
            a[rt1].nxt[0] = -1;
        if (b[nx2].num == 0)
            b[rt2].nxt[1] = -1;
        ok = 0;
    }
    while ((~a[rt1].nxt[1]) && (~b[rt2].nxt[0])) {
        int temp = qu(a[rt1].nxt[1], b[rt2].nxt[0], w + base, base >> 1);
        res += temp;
        a[rt1].num -= temp;
        b[rt2].num -= temp;
        int nx1 = a[rt1].nxt[1], nx2 = b[rt2].nxt[0];
        if (a[nx1].num == 0)
            a[rt1].nxt[1] = -1;
        if (b[nx2].num == 0)
            b[rt2].nxt[0] = -1;
        ok = 0;
    }
    if (ok) {
        ans[cnt++]=w;
        res++;
        a[rt1].num -= res;
        b[rt2].num -= res;
    }
    return res;
}

char s[35];

int main() {
    int t;cin>>t;
    while (t--) {
        int n,x;cin>>n;
        init();
        for (int i = 0; i < n; ++i) {
            scanf("%d",&x);
            for (int j = 30; j >= 0; --j) {
                s[j] = '0' + (x & 1);
                x >>= 1;
            }
            s[31] = '\0';
            ins(a, s, 0, cnt1);
        }
        for (int i = 0; i < n; ++i) {
            scanf("%d",&x);
            for (int j = 30; j > 0; --j) {
                s[j] = '0' + (x & 1);
                x >>= 1;
            }
            s[31] = '\0';
            ins(b, s, 0, cnt2);
        }
        qu(0, 0, 0, 1 << 30);
        sort(ans,ans+cnt);
        for (int i = 0; i < cnt; ++i) {
            printf("%d%c", ans[i], (i == cnt - 1 ? '\n' : ' '));
        }
    }
}

1004 - equation

分析:这是一个分段函数,有n+1段,然后分别算一下每段函数的解是否存在就可以了。写了一年的bug

#include "bits/stdc++.h"

using namespace std;

struct node {
    int up, dw;

    bool friend operator<(node a, node b) {
        node t1 = a;
        node t2 = b;
        if (t1.dw < 0) {
            t1.up *= -1;
            t1.dw *= -1;
        }
        if (t2.dw < 0) {
            t2.up *= -1;
            t2.dw *= -1;
        }
        long long tt1 = (long long) t1.up * t2.dw;
        long long tt2 = (long long) t2.up * t1.dw;
        return tt1 < tt2;
    }

    bool friend operator==(node a, node b) {
        long long t1 = (long long) a.up * b.dw;
        long long t2 = (long long) b.up * a.dw;
        return t1 == t2;
    }
};

vector v, ans;
int a[100004], b[100004];

int main() {
    int T;
    cin >> T;
    while (T--) {
        int n, c;
        scanf("%d%d", &n, &c);
        v.clear();
        ans.clear();
        int A = 0, B = 0;
        for (int i = 1; i <= n; ++i) {
            scanf("%d%d", &a[i], &b[i]);
            v.push_back({-b[i], a[i]});
            A += -a[i];
            B += -b[i];
        }
        B -= c;
        sort(v.begin(), v.end());
        bool ok = 0;
        for (int i = 0; i < v.size() && !ok; ++i) {
            if (A == 0 && B == 0)ok = 1;
            else if (A == 0 && B != 0) {
                A += v[i].dw * 2;
                B -= v[i].up * 2;
                continue;
            } else {
                node t;
                if (B == 0) {
                    t = {0, 1};
                } else {
                    int g = __gcd(A, B);
                    t = {-B / g, A / g};
                }
                node s = {v[i].up, v[i].dw};
                node las;
                if (i != 0)las = {v[i - 1].up, v[i - 1].dw};
                if (i == 0 && (t < s || t == s)) {
                    ans.push_back(t);
                } else if ((t < s || t == s) && (las < t || las == t)) {
                    ans.push_back(t);
                }
                A += v[i].dw * 2;
                B -= v[i].up * 2;
            }
        }
        node t;
        if (A == 0 && B == 0)ok = 1;
        else if (A == 0 && B != 0);
        else if (B == 0) {
            t = {0, 1};
            if (v[v.size() - 1] < t || v[v.size() - 1] == t)ans.push_back(t);
        } else {
            int g = __gcd(abs(A), abs(B));
            t = {-B / g, A / g};
            if (v[v.size() - 1] < t || v[v.size() - 1] == t)ans.push_back(t);
        }
        sort(ans.begin(), ans.end());
        ans.erase(unique(ans.begin(), ans.end()), ans.end());
        if (ok) {
            puts("-1");
        } else {
            printf("%d", ans.size());
            printf("%c", ans.size() == 0 ? '\n' : ' ');
            for (int i = 0; i < ans.size(); ++i) {
                if (ans[i].dw < 0) {
                    ans[i].dw *= -1;
                    ans[i].up *= -1;
                }
                printf("%d/%d%c", ans[i].up, ans[i].dw, (i == ans.size() - 1 ? '\n' : ' '));
            }
        }
    }
}

1005 - permutation 1

分析:首先很容易得到字典序最小的前两位是n,1。那么若(n-2)!>=k前两个就是n,1。那么对于n<=9的预处理打表,n>9的就可以线性推出来了,首先n>9的前两位肯定是n,1。那么按照字典序的关系,第三位的数应该是递增的,并且第三位的数对于的个数应该是fac[3],那么此时比较一下k与fac[n-3]的关系,直接从小到大枚举一下就可以了。

#include "bits/stdc++.h"

using namespace std;
long long fac[24];
int ans[24];
bool vis[24];
int init[10][10004][10];

struct node {
    int d[34];
    int x[34];
    int n;

    bool friend operator<(node a, node b) {
        for (int i = 1; i < a.n; ++i) {
            if (a.d[i] < b.d[i])return 1;
            if (a.d[i] > b.d[i])return 0;
        }
        return 0;
    }
} a[1000000];

vector v;
int cnt;

int main() {
    fac[0] = 1;
    v.resize(30);

    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= 20; ++i) {
        fac[i] = fac[i - 1] * i;
    }
    v[1] = 1;
    for (int i = 2; i <= 9; ++i) {
        v[i] = i;
        for (int j = 1; j <= fac[i]; ++j) {
            for (int k = 1; k < i; ++k) {
                a[j].d[k] = v[k + 1] - v[k];
            }
            for (int k = 1; k <= i; ++k) {
                a[j].x[k] = v[k];
            }
            a[j].n = i;
            next_permutation(v.begin() + 1, v.begin() + i + 1);
        }
        sort(a + 1, a + fac[i] + 1);
        for (int k = 1; k <= min(fac[i], 10000LL); ++k) {
            for (int j = 1; j <= i; ++j) {
                init[i][k][j] = a[k].x[j];
            }
        }
    }
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        scanf("%d%d", &n, &k);
        if (n > 9) {
            memset(vis, 0, sizeof(vis));
            ans[1] = n;
            ans[2] = 1;
            vis[n] = 1;
            vis[1] = 1;
            for (int i = 3; i <= n; ++i) {
                int base;
                for (int j = 1; j <= n; ++j) {
                    if (!vis[j]) {
                        base = j;
                        break;
                    }
                }
                while (k > fac[n - i]) {
                    k -= fac[n - i];
                    base++;
                    while (vis[base])base++;
                }
                ans[i] = base;
                vis[base] = 1;
            }
            for (int i = 1; i <= n; ++i) {
                printf("%d%c", ans[i], (i == n ? '\n' : ' '));
            }
        } else {
            for (int i = 1; i <= n; ++i) {
                printf("%d%c", init[n][k][i], (i == n ? '\n' : ' '));
            }
        }
    }
}

1006 - string matching

exkmp板子。累加一下算个贡献就可以了,答案加上每个位置的lcp,并且对于每位check是否匹配到最后一位,否则答案+1。

#include

using namespace std;


void EX_ten(char *a, char *b, int M, int N, long long *Next, long long *ret) {
    int i, j, k;
    for (j = 0; 1 + j < M && a[j] == a[1 + j]; j++);
    Next[1] = j;
    k = 1;
    for (i = 2; i < M; i++) {
        int Len = k + Next[k], L = Next[i - k];
        if (L < Len - i) {
            Next[i] = L;
        } else {
            for (j = max(0, Len - i); i + j < M && a[j] == a[i + j]; j++);
            Next[i] = j;
            k = i;
        }
    }
    for (j = 0; j < N && j < M && a[j] == b[j]; j++);
    ret[0] = j;
    k = 0;
    for (i = 1; i < N; i++) {
        int Len = k + ret[k], L = Next[i - k];
        if (L < Len - i) {
            ret[i] = L;
        } else {
            for (j = max(0, Len - i); j < M && i + j < N && a[j] == b[i + j]; j++);
            ret[i] = j;
            k = i;
        }
    }
}

char s1[1000005], s2[1000005];
long long ret[1000005];
long long Next[1000005];


int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%s", s1);
        int n = strlen(s1);
        for (int i = 0; i <= n; i++) ret[i] = Next[i] = 0;
        for (int i = 0; i <= n; i++) s2[i] = s1[i];
        EX_ten(s1, s2, n, n, Next, ret);
        long long ans = 0;
        for (int i = 1; i < n; i++) {
            ans += ret[i];
            ans += (ret[i] != n - i);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

1007 - permutation 2

分析:容易得到n,1,n的数据是一个递推式F[N]=F[N-1]+F[N-3],同时还能得到答案和x,y与1,n的差值有关。x可以走到x-2,x-4……1,3……x-3,x-1,即对于样例12 3 9,相当于[4,8],即5 1 5,注意特判一下x=1和y=n就可以了。

#include "bits/stdc++.h"

using namespace std;
const int mod = 998244353;
long long f[100004];

int main() {
    int t;
    f[0] = 0;
    f[1] = 1;
    f[2] = 1;
    for (int i = 3; i < 100004; ++i) {
        f[i] = f[i - 1] + f[i - 3];
        f[i] %= mod;
    }
    cin >> t;
    int n, x, y;
    while (t--) {
        scanf("%d%d%d", &n, &x, &y);
        int dx = x - 1, dy = n - y;
        int pos = n;
        if (dx == 0 && dy == 0) {
            printf("%lld\n", f[pos]);
        } else {
            if (dx)pos -= 1;
            if (dy)pos -= 1;
            pos -= dx;
            pos -= dy;
            pos = max(0, pos);
            if ((x == 1 || y == n) && y - x == 1) {
                puts("1");
            } else printf("%lld\n", f[pos]);
        }
    }
}

 

你可能感兴趣的:(2019 Multi-University Training Contest 5)