ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

20210823模拟赛解题报告

2021-08-23 10:35:32  阅读:165  来源: 互联网

标签:return ++ sc lst 解题 && 20210823 include 模拟


目录

写在前面

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

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

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

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

期望得分:\(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 \times \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!\n"  
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<<"\n";
    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<<"\n";
    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 << "\n";
//        cout << dep[u]<<" "<<dep[v]<<" "<<dep[lca]<<"\n"; 
        Ans = Ans * (Pow(2, len) - 2) % mod;
        tot -= len;
    }
    Ans = Ans * Pow(2, tot) % mod;
    cout << Ans << "\n";
    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 \begin{cases} f(i-1,j) \\ f(i,j-1) \\ f(i-1,j-1)+1 & [s1_i = s2_j] \end{cases} \]

该 DP 时间复杂度和空间复杂度均为 \(O(\left\vert s1 \right\vert\left\vert s2 \right\vert)\)。

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

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

其中,\(nxt(i,ch)\) 表示 \(s2\) 第 \(i\) 位后第一个字母 \(ch\) 出现的位置。
该 DP 的时间复杂度为 \(O(\left\vert s1\right\vert^ 2 )\),空间复杂度为 \(O(\left\vert s1 \right\vert^2 + \left\vert s2 \right\vert \times 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!\n"
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
*/

标签:return,++,sc,lst,解题,&&,20210823,include,模拟
来源: https://www.cnblogs.com/Silymtics/p/15174832.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有