計蒜客 2019 南昌邀請賽網絡賽題解


傳送門:here
https://wenku.baidu.com/view/85ec20aea417866fb94a8e99.html
https://blog.csdn.net/qq_28738419/article/details/80338544

M. Subsequence

可能數據比較水,暴力1e8log(1e5)1e8*log(1e5)就行了。
其實可以先26n26*n得預處理,然後O(1e8)O(1e8)就很穩了。
或者序列自動機。

#include<bits/stdc++.h>
#define eb push_back
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long LL;
const int MXN = 1e5 + 7;
int n, m;
std::vector<int> vs[28];
char ar[MXN], br[1003];
int main() {
    scanf("%s", ar);
    int len = strlen(ar);
    for(int i = 0; i < len; ++i) {
        vs[ar[i]-'a'].eb(i);
    }
    scanf("%d", &n);
    int flag = 1, s = 0, p, tmp;
    while(n --) {
        scanf("%s", br);
        m = strlen(br);
        flag = 1, s = 0;
        for(int i = 0; i < m; ++i) {
            tmp = br[i]-'a';
            if(vs[tmp].size() == 0 || vs[tmp].back() < s) {
                flag = 0; break;
            }
            p = lower_bound(all(vs[tmp]), s) - vs[tmp].begin();
            if(p == (int)vs[tmp].size()) {
                flag = 0; break;
            }
            s = vs[tmp][p] + 1;
        }
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

K. MORE XOR

利用fuck函數找出規律。
然後預處理4個異或值數組即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;

const int MXN = 5e5 + 6;

int n, m;
int ar[MXN], sum[MXN];
int f[105][105], g[105][105], w[105][105];
void fuck() {
    for(int i = 1; i <= 12; ++i) {
        ar[i] = 1LL<<(i-1);
    }
    n = 12;
    for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] ^ ar[i];
    for(int i = 1; i <= n; ++i) {
        for(int j = i; j <= n; ++j) f[i][j] = sum[j] ^ sum[i-1];
    }
    for(int i = 1; i <= n; ++i) {
        for(int j = i; j <= n; ++j) {
            for(int k = i; k <= j; ++k) {
                for(int h = k; h <= j; ++h) {
                    g[i][j] ^= f[k][h];
                }
            }
        }
    }
    for(int i = 1; i <= n; ++i) {
        for(int j = i; j <= n; ++j) {
            for(int k = i; k <= j; ++k) {
                for(int h = k; h <= j; ++h) {
                    w[i][j] ^= g[k][h];
                }
            }
        }
    }
    for(int i = 1; i <= n; ++i) {
        printf("%d   ", w[1][i]);
        bitset<12> a(w[1][i]);
        cout << a << endl;
    }
    printf("\n");
}
int A[MXN][4], B[MXN][4];
int main() {
    //fuck();
    int tim; scanf("%d", &tim);
    while(tim --) {
        scanf("%d", &n); ar[n+1] = 0;
        for(int i = 1; i <= n; ++i) scanf("%d", &ar[i]);
        A[1][0] = ar[1]; B[1][0] = ar[2];
        for(int i = 2; i <= n; ++i) {
            if(i % 4 == 1)A[i][0] = A[i - 1][0] ^ ar[i];
            else A[i][0] = A[i - 1][0];
            if(i % 4 == 1)B[i][0] = B[i - 1][0] ^ ar[i + 1];
            else B[i][0] = B[i - 1][0];
        }
        A[1][1] = ar[2]; B[1][1] = ar[3];
        for(int i = 2; i <= n; ++i) {
            if(i % 4 == 2)A[i][1] = A[i - 1][1] ^ ar[i];
            else A[i][1] = A[i - 1][1];
            if(i % 4 == 2)B[i][1] = B[i - 1][1] ^ ar[i + 1];
            else B[i][1] = B[i - 1][1];
        }
        A[1][2] = ar[3]; B[1][2] = ar[4];
        for(int i = 2; i <= n; ++i) {
            if(i % 4 == 3)A[i][2] = A[i - 1][2] ^ ar[i];
            else A[i][2] = A[i - 1][2];
            if(i % 4 == 3)B[i][2] = B[i - 1][2] ^ ar[i + 1];
            else B[i][2] = B[i - 1][2];
        }
        A[1][3] = ar[4]; B[1][3] = ar[5];
        for(int i = 2; i <= n; ++i) {
            if(i % 4 == 0)A[i][3] = A[i - 1][3] ^ ar[i];
            else A[i][3] = A[i - 1][3];
            if(i % 4 == 0)B[i][3] = B[i - 1][3] ^ ar[i + 1];
            else B[i][3] = B[i - 1][3];
        }
        int m; scanf("%d", &m);
        while(m --) {
            int l, r;
            scanf("%d%d", &l, &r);
            int len = r-l+1, p = len/4 + 1, ans = 0;
            int id = l % 4;
            if(id == 0) id = 3;
            else -- id;
            if(len % 4 == 0) {
                printf("0\n");
            }else if(len % 4 == 1) {
                printf("%d\n", A[r][id]^A[l-1][id]);
            }else if(len % 4 == 3) {
                printf("%d\n", B[r][id]^B[l-1][id]);
            }else {
                printf("%d\n", A[r][id]^A[l-1][id]^B[r][id]^B[l-1][id]);
            }
        }
    }
    return 0;
}

J. Distance on the tree

這不是主席樹裸題嗎?

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;

const int INF = 0x3f3f3f3f;
const int MXN = 2e5 + 7;
const int mod = 998244353;
int n, m, T, ALL;
int ar[MXN], br[MXN];
int up[MXN][22],dep[MXN];
struct lp {
    int l, r, sum;
}cw[MXN*20];
int Root[MXN], tot_z;
struct node {
    int v, nex, w;
}edge[MXN];
int head[MXN], tot_b;
void add_edge(int a, int b, int c) {
    edge[++tot_b] = {b, head[a], c}; head[a] = tot_b;
    edge[++tot_b] = {a, head[b], c}; head[b] = tot_b;
}
void update(int l, int r, int old, int &cur, int p) {
    cw[++tot_z] = cw[old];
    cur = tot_z;
    ++ cw[cur].sum;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(p <= mid) update(l,mid,cw[old].l,cw[cur].l,p);
    else update(mid+1,r,cw[old].r,cw[cur].r,p);
}
void build(int u, int ba, int d, int w) {
    if(w != -1) update(1, ALL, Root[ba], Root[u], w);
    up[u][0] = ba; dep[u] = d; ar[u] = w;
    for(int i = 1; i <= 20; ++i) up[u][i] = up[up[u][i-1]][i-1];
    for(int i = head[u]; ~i; i = edge[i].nex) {
        int v = edge[i].v;
        if(v == ba) continue;
        build(v, u, d + 1, edge[i].w);
    }
}
int LCA(int x,int y) {
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = 20; i >= 0; --i) {
        if(dep[up[x][i]] >= dep[y]) x = up[x][i];
    }
    if(x == y) return x;
    for(int i = 20; i >= 0; --i) {
        if(up[x][i] != up[y][i]) {
            x = up[x][i], y = up[y][i];
        }
    }
    return up[x][0];
}
int z_query(int l,int r,int u,int v,int lca,int k) {
    if(l == r) return cw[u].sum+cw[v].sum-cw[lca].sum*2;
    int mid = (l + r) >> 1;
    if(k <= mid) return z_query(l,mid,cw[u].l,cw[v].l,cw[lca].l,k);
    else {
        int tmp = cw[cw[u].l].sum+cw[cw[v].l].sum-cw[cw[lca].l].sum*2;
        return tmp + z_query(mid+1,r,cw[u].r,cw[v].r,cw[lca].r,k);
    }
}
struct NODE {
    int a, b, c;
}A[MXN];
int main() {
    cw[0] = {0, 0, 0};
    tot_b = -1; memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for(int i = 1, a, b, c; i < n; ++i) {
        scanf("%d%d%d", &a, &b, &c);
        A[i] = {a, b, c};
        br[i] = c;
    }
    sort(br + 1, br + m);
    ALL = unique(br + 1, br + m) - br;
    for(int i = 0; i < m; ++i) {
        A[i].c = lower_bound(br + 1, br + ALL, A[i].c) - br;
        add_edge(A[i].a, A[i].b, A[i].c);
    }
    build(1, 0, 1, -1);
    int x, y, z;
    while(m --) {
        scanf("%d%d%d", &x, &y, &z);
        int lca = LCA(x, y);
        int tmp = lower_bound(br + 1, br + ALL, z) - br;
        if(tmp != ALL && br[tmp] != z) -- tmp;
        x = Root[x], y = Root[y], lca = Root[lca];
        //printf("tmp = %d %d %d %d\n", tmp, x, y, lca);
        int ANS;
        if(tmp == 0) ANS = 0;
        else ANS = z_query(1, ALL, x, y, lca, tmp);
        printf("%d\n", ANS);
    }
    return 0;
}

I. Max answer

複雜度:O(nlog(n))O(nlog(n))
按最小值位置分治。
對於正數找出左邊得最小前綴,右邊得最大前綴。
對於負數找出左邊得最大前綴,右邊得最小前綴。
還有一個細節看代碼。

#include<bits/stdc++.h>
#define endl "\n"
#define fi first
#define se second
#define eb emplace_back
#define mk make_pair
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false);cin.tie(NULL);
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
typedef pair<int, LL> piL;
typedef vector<int> VI;
typedef vector<pii> VPII;

const int MXN = 1e6 + 6;

int n, m;
LL ar[MXN], sum[MXN];
struct TREE {
    LL sum[MXN<<2];
    int pos[MXN<<2], ip;//1小於0大於
    void push_up(int rt) {
        if(ip) {
            if(sum[ls] <= sum[rs]) pos[rt] = pos[ls];
            else pos[rt] = pos[rs];
            sum[rt] = min(sum[ls], sum[rs]);
        }else {
            if(sum[ls] >= sum[rs]) pos[rt] = pos[ls];
            else pos[rt] = pos[rs];
            sum[rt] = max(sum[ls], sum[rs]);
        }
    }
    void build(int l, int r, int rt, LL *a) {
        if(l == r) {
            sum[rt] = a[l];
            pos[rt] = l;
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, ls, a); build(mid+1, r, rs, a);
        push_up(rt);
    }
    piL query(int L, int R, int l, int r, int rt) {
        if(L <= l && r <= R) return mk(pos[rt], sum[rt]);
        int mid = (l + r) >> 1;
        if(L > mid) return query(L, R, mid + 1, r, rs);
        else if(R <= mid) return query(L, R, l, mid, ls);
        else {
            piL a = query(L, mid, l, mid, ls), b = query(mid + 1, R, mid + 1, r, rs);
            if((ip && a.se <= b.se) || (ip == 0 && a.se > b.se)) return a;
            else return b;
        }
    }
}cw1, cw2, cw3;//小大小
LL ans = -1e18;
void solve(int l, int r) {
    if(l >= r) return ;
    int mid = cw3.query(l, r, 1, n, 1).fi;
    if(ar[mid] >= 0) {
        LL a = cw1.query(l, mid, 1, n, 1).fi, b = cw2.query(mid, r, 1, n, 1).fi;
        ans = max(ans, (sum[b]-sum[a-1])*ar[mid]);//細節
    }else {
        LL a = cw2.query(l, mid, 1, n, 1).fi, b = cw1.query(mid, r, 1, n, 1).fi;
        ans = max(ans, (sum[b]-sum[a])*ar[mid]);//細節
    }
    solve(l, mid-1); solve(mid + 1, r);
}
void init() {
    cw1.ip = cw3.ip = 1; cw2.ip = 0;
    cw1.build(1, n, 1, sum);
    cw2.build(1, n, 1, sum);
    cw3.build(1, n, 1, ar);
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        scanf("%lld", &ar[i]);
        ans = max(ans, ar[i]*ar[i]);
        sum[i] = sum[i-1] + ar[i];
    }
    init();
    solve(1, n);
    printf("%lld\n", ans);
    return 0;
}

C. Angry FFF Party

矩陣快速冪預處理。
然後大的暴力,小的狀壓預處理一下就行了。
對於大於2121WW,能選大的一定要先選大的,不然就湊不齊了。

clscls說可以取模做?orzorz

import com.sun.org.apache.bcel.internal.generic.BIPUSH;

import java.math.BigInteger;
import java.util.Scanner;

public class Main {

    static class mat{
        BigInteger[][] ar = new BigInteger[3][3];
    }
    static mat exe(mat a, mat b) {
        mat c = new mat();
        c.ar[0][0] = BigInteger.ZERO;c.ar[0][1] = BigInteger.ZERO;c.ar[1][0] = BigInteger.ZERO;c.ar[1][1] = BigInteger.ZERO;
        for(int k = 0; k < 2; ++k) {
            for(int i = 0; i < 2; ++i) {
                for(int j = 0; j < 2; ++j) {
                    c.ar[i][j] = c.ar[i][j].add(a.ar[i][k].multiply(b.ar[k][j]));
                }
            }
        }
        return c;
    }
    static mat ksm(mat a, int b) {
        mat res = new mat();
        for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) res.ar[i][j] = BigInteger.valueOf(i==j?1:0);
        while(b > 0) {
            if(b%2 == 1) res = exe(res, a);
            a = exe(a, a);
            b /=  2;
        }
        return res;
    }
    public static void main(String[] args) {
        int[] f = new int[35];
        BigInteger[] g = new BigInteger[35];
        f[1] = 1; f[2] = 1;
        for(int i = 3; i <= 30; ++i) f[i] = f[i-1] + f[i-2];
        mat a = new mat(), b = new mat();
        a.ar[0][0] = BigInteger.ONE;a.ar[0][1] = BigInteger.ONE;a.ar[1][0] = BigInteger.ZERO;a.ar[1][1] = BigInteger.ZERO;
        b.ar[0][0] = BigInteger.ONE;b.ar[0][1] = BigInteger.ONE;b.ar[1][0] = BigInteger.ONE;b.ar[1][1] = BigInteger.ZERO;
        g[1] = BigInteger.ONE; g[2] = BigInteger.ONE; g[3] = BigInteger.ONE;
        for(int i = 4; i <= 30; ++i) {
            b.ar[0][0] = BigInteger.ONE;b.ar[0][1] = BigInteger.ONE;b.ar[1][0] = BigInteger.ONE;b.ar[1][1] = BigInteger.ZERO;
            //System.out.println(f[i]);
            b = ksm(b, f[i]-2);
            b = exe(a, b);
            g[i] = b.ar[0][0];
        }
        Scanner cin = new Scanner(System.in);
        int tim = cin.nextInt(), n;
        BigInteger w = new BigInteger("0");
        while(tim != 0) {
            tim --;
            w = cin.nextBigInteger();
            int flag = 1, s = 30;
            int cnt = 0;
            int[] ans = new int[35];
            while(true) {
                if(w.compareTo(BigInteger.valueOf(21)) < 0) {
                    break;
                }
                int p = -1;
                for(int i = s; i >= 1; --i) {
                    if(w.compareTo(g[i]) >= 0) {
                        p = i; break;
                    }
                }
                if(p == -1) {
                    flag = 0; break;
                }
                w = w.subtract(g[p]);
                ans[cnt] = p; ++ cnt;
                s = p - 1;
                if(w.compareTo(BigInteger.ZERO) == 0) {
                    break;
                }
                if(s == 0) {
                    flag = 0; break;
                }
            }
            if(flag == 0) {
                System.out.println(-1);
            }else if(w.compareTo(BigInteger.ZERO) == 0){
                for(int i = cnt-1; i >= 0; --i) {
                    if(i == 0) System.out.println(ans[i]);
                    else System.out.print(ans[i] + " ");
                }
            }else {
                int sta = 1 << s, ANS = 0;
                for(int i = 1; i < sta; ++i) {
                    BigInteger tmp = BigInteger.ZERO;
                    for(int j = 0; j < s; ++j) {
                        if((i&(1<<j)) != 0) {
                            tmp = tmp.add(g[j+1]);
                        }
                    }
                    if(tmp.compareTo(w) == 0) {
                        flag = -1;
                        ANS = i;
                        break;
                    }
                }
                if(flag == -1) {
                    for(int j = s-1; j >= 0; --j) {
                        if((ANS&(1<<j)) != 0) {
                            ans[cnt] = j+1; ++ cnt;
                        }
                    }
                    for(int i = cnt-1; i >= 0; --i) {
                        if(i == 0) System.out.println(ans[i]);
                        else System.out.print(ans[i] + " ");
                    }
                }else {
                    System.out.println(-1);
                }
            }
        }
    }
}

D.Match Stick Game

dp1[i][j]dp1[i][j]ii個棒子形成jj位數的最大數字
dp2[i][j]dp2[i][j]ii個棒子形成jj位數的最小數字

dp[i][j]dp[i][j]ii個火柴組成前jj項的表達式的最大值
轉移就是:枚舉這一項前面的符號是正號還是負號

#include<bits/stdc++.h>
#define endl "\n"
#define fi first
#define se second
#define eb emplace_back
#define mk make_pair
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false);cin.tie(NULL);
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
typedef vector<int> VI;
typedef vector<pii> VPII;

const LL INFLL = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
const int MOD = 998244353;
const int MXE = 2e6 + 6;
const int MXN = 1e3 + 6;

int n, m;
char s[MXN];
int ar[MXN], br[MXN], wei[MXN];
int is[20] = {6,2,5,5,4,5,6,3,7,6};
LL dp1[MXN][15], dp2[MXN][15];//大小
//dp1[i][j]i個棒子j位數的最大數字
LL dp[MXN][MXN];//i個火柴組成前j項的表達式的最大值
int get_wei(int x) {
    int cnt = 0;
    while(x) {
        ++ cnt; x /= 10;
    }
    return cnt;
}
/*
1 2 3 4 5 6 7 8 9 0
2 5 5 4 5 6 3 7 6 6
*/
void init() {
    memset(dp2, 0x3f, sizeof(dp2));
    int all = 701;
    dp2[0][0] = 0;
    for(int i = 2; i <= all; ++i) {
        for(int j = 1; j <= 10; ++j) {
            dp1[i][j] = max(dp1[i][j], dp1[i-2][j-1] * 10 + 1);
            if(i >= 3) dp1[i][j] = max(dp1[i][j], dp1[i-3][j-1] * 10 + 7);
            if(i >= 4) dp1[i][j] = max(dp1[i][j], dp1[i-4][j-1] * 10 + 4);
            if(i >= 5) dp1[i][j] = max(dp1[i][j], dp1[i-5][j-1] * 10 + 5);
            if(i >= 6) dp1[i][j] = max(dp1[i][j], dp1[i-6][j-1] * 10 + 9);
            if(i >= 7) dp1[i][j] = max(dp1[i][j], dp1[i-7][j-1] * 10 + 8);
 
            dp2[i][j] = min(dp2[i][j], dp2[i-2][j-1] * 10 + 1);
            if(i >= 3) dp2[i][j] = min(dp2[i][j], dp2[i-3][j-1] * 10 + 7);
            if(i >= 4) dp2[i][j] = min(dp2[i][j], dp2[i-4][j-1] * 10 + 4);
            if(i >= 5) dp2[i][j] = min(dp2[i][j], dp2[i-5][j-1] * 10 + 2);
            if(i >= 6 && (j == 1 || dp2[i-6][j-1] != 0)) dp2[i][j] = min(dp2[i][j], dp2[i-6][j-1] * 10 + 0);
            if(i >= 7) dp2[i][j] = min(dp2[i][j], dp2[i-7][j-1] * 10 + 8);
        }
    }
}
int main() {
    init();
    int tim; scanf("%d", &tim);
    while(tim --) {
        scanf("%d%s", &n, s);
        int m = 0, cnt = 0;
        int all = 0;
        for(int i = 0; i < n; ++i) {
            if(isdigit(s[i])) all += is[s[i]-'0'];
            else if(s[i] == '+') all += 2;
            else if(s[i] == '-') ++ all;
            if(isdigit(s[i]) && i != n - 1) cnt = cnt * 10 + s[i] - '0';
            else {
                if(i == n-1) cnt = cnt * 10 + s[i] - '0';
                ar[m++] = cnt;
                cnt = 0;
                br[m-1] = (s[i]=='+');
            }
        }
        for(int i = 0; i < m; ++i) wei[i+1] = get_wei(ar[i]);
        //for(int i = 0; i < m-1; ++i) printf("%d\n", br[i]);
        //printf("**\n");
        memset(dp, -1, sizeof(dp));
        for(int i = 2; i <= all; ++i) dp[i][1] = dp1[i][wei[1]];
        //printf("[%d]\n", dp[3][1]);
        for(int i = 5; i <= all; ++i) {
            for(int j = 2; j <= m; ++j) {
                for(int k = 2; k <= i-2; ++k) {
                    if(dp[i-2-k][j-1]!=-1)dp[i][j] = max(dp[i][j], dp[i-2-k][j-1] + dp1[k][wei[j]]);
                }
                for(int k = 2; k <= i-1; ++k) {
                    if(dp[i-1-k][j-1]!=-1)dp[i][j] = max(dp[i][j], dp[i-1-k][j-1] - dp2[k][wei[j]]);
                }
            }
        }
        /*
        1 2 3 4 5 6 7 8 9 0
        2 5 5 4 5 6 3 7 6 6
        */
        //printf("[%d] [%d]\n", dp[3][1], dp[5][2]);
        printf("%lld\n", dp[all][m]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章