zoukankan      html  css  js  c++  java
  • 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
    */
    
  • 相关阅读:
    博客园
    未释放的已删除文件
    ssh连接缓慢
    剑指 Offer 38. 字符串的排列
    剑指 Offer 37. 序列化二叉树
    剑指 Offer 50. 第一个只出现一次的字符
    剑指 Offer 36. 二叉搜索树与双向链表
    剑指 Offer 35. 复杂链表的复制
    剑指 Offer 34. 二叉树中和为某一值的路径
    剑指 Offer 33. 二叉搜索树的后序遍历序列
  • 原文地址:https://www.cnblogs.com/Silymtics/p/15174832.html
Copyright © 2011-2022 走看看