• 20210823模拟赛解题报告


    写在前面

    这套题一如既往的魔幻,值得喷的地方依旧很多。

    第一题小清新思维题还好。

    第二题最长公共子序列是个原题!

    第三题是个爆搜大模拟,数据和题解还都是错的!

    期望得分:(100pts + 60pts + 40pts = 200pts)

    实际得分:(30pts + 60pts + 40pts = 130pts)

    T1 答案没取模挂惨了/kk

    T2 只会 (O(nm)) 做法,正解是 (O(n^2))

    T3 在洛谷上能跑到 50pts,众所周知机房机子跑的慢。

    补题通道:

    T1 T2 T3
    U175818 road U175823 lcs U175820 cube

    T1

    Solution

    简述题意就是 (n) 个点 (n) 条边,然后对无向边重定向。

    对于一个环,当重定向后仍是一个环时,仅有两种情况(所有边全朝一个方向)。
    如果这个环只有 (x) 个点,那么这个环一共有 (2^x - 2) 种合法方案。

    不在环上的边怎么都无所谓。

    可以把每个边的方向看做 01 两种情况,那么设第 (i) 个环上有 (x_i) 个边(点),一共有 (k) 个环,不在环上的边有 (y) 条,那么答案为:

    [2^y imes prod_{i=1}^k (2^{x_i}-2) pmod {10^9+7} ]

    至于判断环……

    我不会 dfs,也没用 tarjan,写的生成树 + 树剖。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<queue>
    #include<vector>
    #include<map>
    #include<algorithm>
    #define LL long long
    #define orz cout << "lkp AK IOI!
    "  
    using namespace std;
    const LL MAXN = 1e5 + 500;
    const LL INF = 1e9 + 7;
    const LL mod = 1e9 + 7;
    
    struct edge {
        LL to, nxt;
    }e[MAXN << 1], E[MAXN];
    LL head[MAXN], num_edge = 1, sc = 0;
    
    LL n, m, Cnt = 0;
    LL dep[MAXN], Fa[MAXN];
    LL fath[MAXN], siz[MAXN], son[MAXN], top[MAXN];
    bool vis[MAXN];
    
    LL read() {
        LL f = 0, s = 0;
        char ch = getchar();
        while(!isdigit(ch)) f = (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 3) + (s << 1) + ch - '0', ch = getchar();
        return f ? -s : s;
    }
    
    LL find(LL x) { return Fa[x] == x ? x : Fa[x] = find(Fa[x]); }
    void add_edge(LL from, LL to) { e[++num_edge] = (edge){to, head[from]}, head[from] = num_edge; }
    
    void dfs(LL u, LL fa) { 
    //    cout<<u<<" "<<fa<<"
    ";
        vis[u] = true;
        dep[u] = dep[fa] + 1, fath[u] = fa, siz[u] = 1;
        for(LL i = head[u]; i; i = e[i].nxt) {
            LL v = e[i].to;
            if(v == fa) continue;
            dfs(v, u);
            siz[u] += siz[v]; 
            if(siz[son[u]] < siz[v]) son[u] = v;
        }
    }
    
    void dfs2(LL u, LL tp) {
        top[u] = tp;
        if(son[u]) dfs2(son[u], tp);
        for(LL i = head[u]; i; i = e[i].nxt) {
            LL v = e[i].to;
            if(v == fath[u] || v == son[u]) continue;
            dfs2(v, v);
        }
    } 
    
    LL Get_LCA(LL x, LL y) {
        while(top[x] != top[y]) dep[top[x]] < dep[top[y]] ? y = fath[top[y]] : x = fath[top[x]];
        return dep[x] < dep[y] ? x : y;
    }
    
    LL Pow(LL x, LL p) {
        LL res = 1;
        while(p) {
            if(p & 1) res = res * x % mod;
            x = x * x % mod;
            p >>= 1;
        }
        return res;
    }
    
    int main() {
    //    freopen("road.in","r",stdin);
    //    freopen("road.out","w",stdout);
        n = read();
        for(LL i = 1; i <= n; ++i) Fa[i] = i;
        for(LL i = 1, x; i <= n; ++i) {
            x = read();
            LL uf = find(i), vf = find(x);
            if(uf != vf) {
                add_edge(i, x), add_edge(x, i);
                Fa[uf] = vf;
            } else {
                E[++sc] = (edge){i, x};
            }
        }
    //    cout<<sc<<"
    ";
        for(LL i = 1; i <= n; ++i) {
            if(!vis[i]) {
                dfs(i, 0);
                dfs2(i, i);
            }
        }
        int Ans = 1, tot = n;
    //    for(int i = 1; i <= n; ++i) cout<<dep[i]<<" "; puts("");
        for(LL i = 1; i <= sc; ++i) {
            LL u = E[i].to, v = E[i].nxt;
            if(dep[u] < dep[v]) swap(u, v);
            int lca = Get_LCA(u, v);
            LL len = dep[u] + dep[v] - 2 * dep[lca] + 1;
    //        cout << u << " " << v << " " << lca<<" " << len << "
    ";
    //        cout << dep[u]<<" "<<dep[v]<<" "<<dep[lca]<<"
    "; 
            Ans = Ans * (Pow(2, len) - 2) % mod;
            tot -= len;
        }
        Ans = Ans * Pow(2, tot) % mod;
        cout << Ans << "
    ";
        return 0;
    }
    /*
    5
    2 3 1 5 4
    
    8
    8 1 1 2 2 3 3 7
    */
    

    T2

    Solution

    一直把 T2 当场最长公共上升子序列了,淦。

    考虑朴素 DP,记 (f(i,j)) 表示 (s1) 匹配到了第 (i) 位,(s2) 匹配到了第 (j) 位,的最长公共子序列长度,那么我们有如下递推关系:

    [f(i,j) = max egin{cases} f(i-1,j) \ f(i,j-1) \ f(i-1,j-1)+1 & [s1_i = s2_j] end{cases} ]

    该 DP 时间复杂度和空间复杂度均为 (O(leftvert s1 ightvertleftvert s2 ightvert))

    由于 (s2) 较长,考虑改变 DP 的角度。
    (g(i,j)) 表示 (s1) 匹配到了第 (i) 位,最长公共子序列长度为 (j) 时,(s2) 可能匹配到的最左下标,那么我们有如下递推关系:

    [g(i,j) = max egin{cases} g(i-1,j) \ nxt(g(i-1,j-1),s1_i) end{cases} ]

    其中,(nxt(i,ch)) 表示 (s2)(i) 位后第一个字母 (ch) 出现的位置。
    该 DP 的时间复杂度为 (O(leftvert s1 ightvert^ 2 )),空间复杂度为 (O(leftvert s1 ightvert^2 + leftvert s2 ightvert imes 26))

    Code

    /*
    Work by: Suzt_ilymics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 1e6+500;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    char s1[1010], s2[MAXN];
    int n, m, Ans = 0;
    int nxt[MAXN][27], lst[27];
    int f[1010][1010];
    
    int read(){
        int s = 0, f = 0;
        char ch = getchar();
        while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
        return f ? -s : s;
    }
    
    int main()
    {
        cin >> s1 + 1 >> s2 + 1;
        n = strlen(s1 + 1), m = strlen(s2 + 1);
        for(int i = 0; i < 26; ++i) lst[i] = m + 1;
        for(int i = 0; i < 26; ++i) nxt[m+1][i] = m + 1;
        for(int i = m; i >= 1; --i) {
            memcpy(nxt[i], nxt[i + 1], sizeof nxt[i]);
            nxt[i][s2[i] - 'a'] = i;
    //        lst[s2[i] - 'a'] = i;
    //        for(int j = 0; j < 26; ++j) {
    //            nxt[i][j] = lst[j];
    //        }
        }
        memset(f, 0x3f, sizeof f);
        f[1][1] = nxt[1][s1[1] - 'a'];
        for(int i = 0; i <= n; ++i) f[i][0] = 0;
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) {
                if(f[i - 1][j - 1] <= m) f[i][j] = min(f[i - 1][j], nxt[f[i - 1][j - 1] + 1][s1[i] - 'a']);
                else f[i][j] = f[i - 1][j];
                if(f[i][j] <= m) Ans = max(Ans, j);
            }
        }
        printf("%d", Ans);
        return 0;
    }
    
    

    T3

    Solution

    按照题意模拟即可,搜的时候先搜字典序小的,记录一个 (lst) 存上一次操作类型。

    题解说前九操作和后九种操作一样,加上它们不会更优,所以可以不考虑。那爆搜就完了啊!

    但是样例显然可以 1 16,比一个 2 更优(题目自己说的)。

    所以题解的思路是错的,然后跑出来的数据也是错的。

    不过值得借鉴的一点是,题解用了一个很 nb 的置换群,我不会,但码量贼短。要知道我自己考场上用一个半小时打了 8KB

    Code

    代码是正确题意的代码,但是复杂度是 (O(18^7)) 还带一个常数,我没有想到怎么剪枝。

    题目数据还是错的,如果想通过本题只需打前九个操作的部分即可。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<queue>
    #include<vector>
    #include<map>
    #include<algorithm>
    #define orz cout << "lkp AK IOI!
    "
    using namespace std;
    const int MAXN = 1e5 + 500;
    const int INF = 1e9 + 7;
    const int mod = 1e9 + 7;
    
    struct node {
        int c[26];
        bool operator < (const node &b) const { 
            for(int i = 1; i <= 24; ++i) {
                if(c[i] != b.c[i]) {
                    return c[i] < b.c[i];
                }
            }
            return true;
         }
    }base;
    
    int n;
    int stc[100], sc = 0;
    map<node, bool> Map;
    
    int read() {
        int f = 0, s = 0;
        char ch = getchar();
        while(!isdigit(ch)) f = (ch == '-'), ch = getchar();
        while(isdigit(ch)) s = (s << 3) + (s << 1) + ch - '0', ch = getchar();
        return f ? -s : s;
    }
    
    namespace Work {
        node A1(node x) {
            int res = x.c[2];
            x.c[2] = x.c[1], x.c[1] = x.c[3], x.c[3] = x.c[4], x.c[4] = res;
            int p1 = x.c[24], p2 = x.c[23];
            x.c[24] = x.c[9], x.c[23] = x.c[10];
            x.c[9] = x.c[5], x.c[10] = x.c[6];
            x.c[5] = x.c[13], x.c[6] = x.c[14];
            x.c[13] = p1, x.c[14] = p2;
            return x;
        }
        node A2(node x) { x = A1(x), x = A1(x); return x; }
        node A3(node x) { x = A1(x), x = A1(x), x = A1(x); return x; }
        node B1(node x) {
            int res = x.c[10];
            x.c[10] = x.c[9], x.c[9] = x.c[11], x.c[11] = x.c[12], x.c[12] = res;
            int p1 = x.c[1], p2 = x.c[3];
            x.c[1] = x.c[21], x.c[3] = x.c[23];
            x.c[21] = x.c[17], x.c[23] = x.c[19];
            x.c[17] = x.c[5], x.c[19] = x.c[7];
            x.c[5] = p1, x.c[7] = p2;
            return x;
        }
        node B2(node x) { x = B1(x), x = B1(x); return x; }
        node B3(node x) { x = B1(x), x = B1(x), x = B1(x); return x; }
        node C1(node x) {
            int res = x.c[5];
            x.c[5] = x.c[7], x.c[7] = x.c[8], x.c[8] = x.c[6], x.c[6] = res;
            int p1 = x.c[3], p2 = x.c[4];
            x.c[3] = x.c[12], x.c[4] = x.c[10];
            x.c[12] = x.c[18], x.c[10] = x.c[17];
            x.c[18] = x.c[13], x.c[17] = x.c[15];
            x.c[13] = p1, x.c[15] = p2;
            return x;
        }
        node C2(node x) { x = C1(x), x = C1(x); return x; }
        node C3(node x) { x = C1(x), x = C1(x), x = C1(x); return x; }
        node D1(node x) {
            int res = x.c[13];
            x.c[13] = x.c[15], x.c[15] = x.c[16], x.c[16] = x.c[14], x.c[14] = res;
            int p1 = x.c[4], p2 = x.c[2];
            x.c[4] = x.c[8], x.c[2] = x.c[6];
            x.c[8] = x.c[20], x.c[6] = x.c[18];
            x.c[20] = x.c[24], x.c[18] = x.c[22];
            x.c[24] = p1, x.c[22] = p2;
            return x;
        }
        node D2(node x) { x = D1(x), x = D1(x); return x; }
        node D3(node x) { x = D1(x), x = D1(x), x = D1(x); return x; }
        node E1(node x) {
            int res = x.c[21];
            x.c[21] = x.c[23], x.c[23] = x.c[24], x.c[24] = x.c[22], x.c[22] = res;
            int p1 = x.c[19], p2 = x.c[20];
            x.c[19] = x.c[9], x.c[20] = x.c[11];
            x.c[9] = x.c[2], x.c[11] = x.c[1];
            x.c[2] = x.c[11], x.c[1] = x.c[14];
            x.c[11] = p1, x.c[14] = p2;
            return x;
        } 
        node E2(node x) { x = E1(x), x = E1(x); return x; }
        node E3(node x) { x = E1(x), x = E1(x), x = E1(x); return x; }
        node F1(node x) {
            int res = x.c[17];
            x.c[17] = x.c[19], x.c[19] = x.c[20], x.c[20] = x.c[18], x.c[18] = res;
            int p1 = x.c[7], p2 = x.c[8];
            x.c[7] = x.c[11], x.c[8] = x.c[12];
            x.c[11] = x.c[22], x.c[12] = x.c[21];
            x.c[22] = x.c[15], x.c[21] = x.c[16];
            x.c[15] = p1, x.c[16] = p2;
            return x;
        }
        node F2(node x) { x = F1(x), x = F1(x); return x; }
        node F3(node x) { x = F1(x), x = F1(x), x = F1(x); return x; }
    }
    using namespace Work;
    
    bool Check(node x) {
        for(int i = 4; i <= 24; i += 4) {
            int p = i / 4;
            if(x.c[i - 3] == x.c[i - 2] && x.c[i - 2] == x.c[i - 1] && x.c[i - 1] == x.c[i]) continue;
            return false;
        }
        return true;
    }
    
    namespace Subtask1 {
        void Solve() {
            node x = base;
            if(Check(A1(x))) puts("1");
            else if(Check(A2(x))) puts("2");
            else if(Check(A3(x))) puts("3");
            else if(Check(B1(x))) puts("4");
            else if(Check(B2(x))) puts("5");
            else if(Check(B3(x))) puts("6");
            else if(Check(C1(x))) puts("7");
            else if(Check(C2(x))) puts("8");
            else if(Check(C3(x))) puts("9");
            else if(Check(D1(x))) puts("10");
            else if(Check(D2(x))) puts("11");
            else if(Check(D3(x))) puts("12");
            else if(Check(E1(x))) puts("13");
            else if(Check(E2(x))) puts("14");
            else if(Check(E3(x))) puts("15");
            else if(Check(F1(x))) puts("16");
            else if(Check(F2(x))) puts("17");
            else if(Check(F3(x))) puts("18");
            else puts("-1");
        }
    }
    
    bool Flag = false;
    void dfs(int stp, node now_, int lst) {
        // if(Map[now_]) {
        //     Map[now_] = true;
        //     return ;
        // }
        if(Check(now_)) {
           Flag = true;
           return ;
        }
        if(stp > n) return ;
        if(lst != 1 && lst != 2 && lst != 3)  { stc[++sc] = 1;  dfs(stp + 1, A1(now_), 1);  if(Flag) return ; sc--; }
        if(lst != 1 && lst != 2 && lst != 3)  { stc[++sc] = 2;  dfs(stp + 1, A2(now_), 2);  if(Flag) return ; sc--; }
        if(lst != 1 && lst != 2 && lst != 3)  { stc[++sc] = 3;  dfs(stp + 1, A3(now_), 3);  if(Flag) return ; sc--; }
        if(lst != 4 && lst != 5 && lst != 6)  { stc[++sc] = 4;  dfs(stp + 1, B1(now_), 4);  if(Flag) return ; sc--; }
        if(lst != 4 && lst != 5 && lst != 6)  { stc[++sc] = 5;  dfs(stp + 1, B2(now_), 5);  if(Flag) return ; sc--; }
        if(lst != 4 && lst != 5 && lst != 6)  { stc[++sc] = 6;  dfs(stp + 1, B3(now_), 6);  if(Flag) return ; sc--; }
    //    if(n > 3) return ;
        if(lst != 7 && lst != 8 && lst != 9)  { stc[++sc] = 7;  dfs(stp + 1, C1(now_), 7);  if(Flag) return ; sc--; }
        if(lst != 7 && lst != 8 && lst != 9)  { stc[++sc] = 8;  dfs(stp + 1, C2(now_), 8);  if(Flag) return ; sc--; }
        if(lst != 7 && lst != 8 && lst != 9)  { stc[++sc] = 9;  dfs(stp + 1, C3(now_), 9);  if(Flag) return ; sc--; }
        if(lst != 10 && lst != 11 && lst != 12) { stc[++sc] = 10; dfs(stp + 1, D1(now_), 10); if(Flag) return ; sc--; }
        if(lst != 10 && lst != 11 && lst != 12) { stc[++sc] = 11; dfs(stp + 1, D2(now_), 11); if(Flag) return ; sc--; }
        if(lst != 10 && lst != 11 && lst != 12) { stc[++sc] = 12; dfs(stp + 1, D3(now_), 12); if(Flag) return ; sc--; }
        if(lst != 13 && lst != 14 && lst != 15) { stc[++sc] = 13; dfs(stp + 1, E1(now_), 13); if(Flag) return ; sc--; }
        if(lst != 13 && lst != 14 && lst != 15) { stc[++sc] = 14; dfs(stp + 1, E2(now_), 14); if(Flag) return ; sc--; }
        if(lst != 13 && lst != 14 && lst != 15) { stc[++sc] = 15; dfs(stp + 1, E3(now_), 15); if(Flag) return ; sc--; }
        if(lst != 16 && lst != 17 && lst != 18) { stc[++sc] = 16; dfs(stp + 1, F1(now_), 16); if(Flag) return ; sc--; }
        if(lst != 16 && lst != 17 && lst != 18) { stc[++sc] = 17; dfs(stp + 1, F2(now_), 17); if(Flag) return ; sc--; }
        if(lst != 16 && lst != 17 && lst != 18) { stc[++sc] = 18; dfs(stp + 1, F3(now_), 18); if(Flag) return ; sc--; }
    }
    
    int main() {
    //    freopen("cube.in","r",stdin);
    //    freopen("cube.out","w",stdout);
        n = read();
        for(int i = 1; i <= 24; ++i) {
            base.c[i] = read();
        }
        if(n == 1) { Subtask1::Solve(); }
        else {
            dfs(1, base, 0);
            for(int i = 1; i <= sc; ++i)  printf("%d ", stc[i]);
            puts("");
        }
        return 0;
    }
    /*
    2
    1 1 1 1
    4 4 2 2
    6 6 3 3 
    3 3 6 6 
    5 5 5 5
    4 4 2 2
    */
    
  • 相关阅读:
    求集合的子集总结及案例
    静态资源(JS/CSS)存储在localStorage
    js 数组&字符串 去重
    跨域iframe高度计算
    Xshell5连接虚拟机出现连Could not connect to '192.168.47.128' (port 22): Connection failed,解决办法
    sql server中常用方法函数
    sql中union和union all的用法
    python(1) -文件操作
    python(1)
    python(1)
  • 原文地址:https://www.cnblogs.com/Silymtics/p/15174832.html
Copyright © 2020-2023  润新知