• GRYZ20211102模拟赛解题报告


    期望得分:(0 sim 100+100+30 = 230pts)
    实际得分:(10 + 60 + 10 = 80pts)

    评价一下这套题。

    @Suzt_ilymtics
    什么垃圾模拟题题面描述不清啊!出大模拟还不给大样例做nm 啊! /fn

    出题人你没有妈妈,你出个部分分不给部分分数据你是人吗?是人吗? /fn

    @斜揽残箫
    为啥会有伞兵模拟赛第一题出大模拟并且不告诉你细节啊 /fn

    题面无细节,尤其是 T2。

    @KnightL
    你家一个菜市场只卖一种菜啊。

    这哪是阅读理解啊,这就是作文续写啊。

    第一次体验到挂分的快乐,T2 因为少了一个 if 丢了 40pts。

    T3 大方向对了(不过一直在想怎么 (mathcal O(n)) Check),但没想到题解的约束比我的结论还紧凑,然后直接 (3^{14}) Check。还是太菜了。

    T1 模拟也有一堆细节没处理好,犯得错误放在代码开头了。

    T1 T2 T3
    T208733 robo T208734 expand T208735 birthday

    A robo

    大模拟。

    注意细节,按照题意模拟即可。(((

    这里赛后发现了一个问题,就是洛谷用 getline 读入的时候会读入回车 ,而 lemon 不会。

    其他的看代码吧。哦吼吼我的 200+,7kb 的代码!

    /*
    Work by: Suzt_ilymtics
    Problem: 不知名屑题
    Knowledge: 垃圾算法
    Time: O(能过)
    大模拟,做nm! 
    
    
    1、WG 函数返回错误,应直接返回而非 break。 
    2、字符串的奇怪问题。 
    3、洛谷 getline 读回车,lemon 不读
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<string>
    #define LL long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 1e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    struct Robot {
        int x, y, a, b, c;
        int atk, fx, soc;
    }R;
    
    int n, m, K;
    string s;
    int stc[MAXN], sc = 0; // 弹夹。 
    int Map[222][222], blood[222][222];
    bool flag = false, Flag = false;
    
    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;
    }
    
    void Clear() {
        R.x = R.y = R.a = R.b = R.c = R.atk = R.fx = R.soc = 0; 
        n = 0, m = 0, K = 0; s.clear();
        sc = 0, Flag = false, flag = false;
        memset(stc, false, sizeof stc);
        memset(Map, false, sizeof Map);
        memset(blood, false, sizeof blood);
    }
    
    void Get_Map() {
        n = read(), m = read();
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                Map[i][j] = read();
                if(Map[i][j] == 2) blood[i][j] = 2;
            }
        }
    }
    
    void Get_Robot() { // 初始化机器人信息 
        R.x = read() + 1, R.y = read() + 1, R.a = read(), R.b = read(), R.c = read(), K = read();
        R.atk = 0, R.fx = 0, R.soc = 0, sc = 0; // 初始炮口朝向和机器人朝向为 0 (0,1,2,3 分别表示上左下右),弹夹初始容量为 0 
    }
    
    void Turn_ATK() { // FT x
        int x = s[3] - '0';
        if(s[3] < '0' || s[3] > '9') return (void)(flag = true); 
        if(s[4] == '.') return (void)(flag = true);
        if(s[4] >= '0' && s[4] <= '9') return (void)(flag = true);
        if(x != 0 && x != 1) return (void)(flag = true);
        if(x == 0) R.atk = (R.atk + 1) % 4;
        else R.atk = (R.atk + 3) % 4;
    } 
    
    void Push_ATK() { // FF i
        int x = s[3] - '0';
        if(s[3] < '0' || s[3] > '9') return (void)(flag = true); 
        if(s[4] == '.') return (void)(flag = true);
        if(s[4] >= '0' && s[4] <= '9') return (void)(flag = true);
        if(x != 0 && x != 1) return (void)(flag = true);
        if(x == 0) {
            if(R.c == 0) return ;
            if(sc == R.a) return (void)(flag = true);
            R.c --, stc[++sc] = 1;
        } else {
            if(R.b == 0) return ;
            if(sc == R.a) return (void)(flag = true);
            R.b --, stc[++sc] = 2;
        }
    }
    
    void Attack() { // FE
        int len = s.length();
        if(s.length() > 3) return (void)(flag = true);
        if(sc == 0) return ;
        int x = stc[sc--];
        if(R.atk == 0) {
            for(int i = R.x - 1; i; --i) {
                if(Map[i][R.y] == 1) break;
                if(blood[i][R.y] > 0) {
                    blood[i][R.y] -= x;
                    if(blood[i][R.y] <= 0) Map[i][R.y] = 0, R.soc ++;
                    break;
                }
            }
        } else if(R.atk == 1) {
            for(int j = R.y - 1; j; --j) {
                if(Map[R.x][j] == 1) break;
                if(blood[R.x][j] > 0) {
                    blood[R.x][j] -= x;
                    if(blood[R.x][j] <= 0) Map[R.x][j] = 0, R.soc ++;
                    break;
                }
            }
        } else if(R.atk == 2) {
            for(int i = R.x + 1; i <= n; ++i) {
                if(Map[i][R.y] == 1) break;
                if(blood[i][R.y] > 0) {
                    blood[i][R.y] -= x;
                    if(blood[i][R.y] <= 0) Map[i][R.y] = 0, R.soc ++;
                    break;
                }
            }
        } else if(R.atk == 3) {
            for(int j = R.y + 1; j <= m; ++j) {
                if(Map[R.x][j] == 1) break;
                if(blood[R.x][j] > 0) {
                    blood[R.x][j] -= x;
                    if(blood[R.x][j] <= 0) Map[R.x][j] = 0, R.soc ++;
                    break;
                }
            }
        }
    }
    
    void Turn_itself() { // WT x
        int x = s[3] - '0';
        if(s[3] < '0' || s[3] > '9') return (void)(flag = true); 
        if(s[4] == '.') return (void)(flag = true);
        if(s[4] >= '0' && s[4] <= '9') return (void)(flag = true);
        if(x != 0 && x != 1) return (void)(flag = true);
        if(x == 0) R.fx = (R.fx + 1) % 4;
        else R.fx = (R.fx + 3) % 4;
    }
    
    void Walk() { // WG y
        if(s[4] == '.') return (void)(flag = true);
        int x = 0;
        int len = s.length() - 1;
        for(int i = 3; i < len; ++i) {
            if(s[i] >= '0' && s[i] <= '9') x = x * 10 + s[i] - '0';
            else return (void)(flag = true);
        }
        if(R.fx == 0) {
            int now = R.x;
            while(x) {
                if(now - 1 < 1 || Map[now - 1][R.y] != 0) return (void)(flag = true);
                now --, x--;
            }
            R.x = now;
        } else if(R.fx == 1) {
            int now = R.y;
            while(x) {
                if(now - 1 < 1 || Map[R.x][now - 1] != 0) return (void)(flag = true);
                now --, x--;
            }
            R.y = now;
        } else if(R.fx == 2) {
            int now = R.x;
            while(x) {
                if(now + 1 > n || Map[now + 1][R.y] != 0) return (void)(flag = true);
                now ++, x--;
            }
            R.x = now;
        } else if(R.fx == 3) {
            int now = R.y;
            while(x) {
                if(now + 1 > m || Map[R.x][now + 1] != 0) return (void)(flag = true);
                now ++, x--;
            }
            R.y = now;
        }
    }
    
    void Start_Play() {
        Get_Map();
        Get_Robot();
        getline(cin, s);
    //    char ch = getchar(); 
        for(int i = 1; i <= K; ++i) {
    //        s.clear();
            getline(cin, s);
    //        char ch = getchar();
    //        while(ch != '
    ') s += ch, ch = getchar(); 
    //        cout<<s<<"
    ";
    //        cout<<"flag "<<flag<<" "<<R.x<<" "<<R.y<<"
    ";
            if(Flag || flag) continue;
            if(s[0] == 'F' && s[1] == 'T') Turn_ATK();
            else if(s[0] == 'F' && s[1] == 'F') Push_ATK();
            else if(s[0] == 'F' && s[1] == 'E') Attack();
            else if(s[0] == 'W' && s[1] == 'T') Turn_itself();
            else if(s[0] == 'W' && s[1] == 'G') Walk();
            else if(s[0] == 'E' && s[1] == 'N' && s[2] == 'D') Flag = true;
            else flag = true;
        }
        if(!Flag) flag = true;
        if(flag) puts("ERROR");
        else puts("Complete");
        printf("%d %d
    ", R.x - 1, R.y - 1);
        printf("%d
    ", R.soc);
        printf("%d %d %d %d
    ", R.atk, R.fx, R.b, R.c);
    }
    
    int main()
    {
    //    freopen("robo.in","r",stdin);
    //    freopen("robo.out","w",stdout);
    	int T = read();
    	while(T--) Clear(), Start_Play();
        return 0;
    }
    /*
    
    1
    5 5
    2 0 0 0 0
    0 0 0 0 0
    0 0 1 0 0
    0 0 0 0 0
    0 0 0 0 0
    4 4 3 1 1 7
    WG 3
    WT 0
    WG 4
    FF 1
    FE 
    END
    END
    
    */
    

    B expand

    首先预处理一个二维前缀和。

    然后在枚举每一个位置枚举每一个 (s) 处理出在某个位置的体格。

    然后枚举每一个要到的点(包括起点),直接 bfs 跑最短路,预处理出到其他点的最短距离及最大体格之和。

    然后你考虑状压 DP。

    (f[S][i]) 表示已经到过的位置状态为 (S),最后一个到的点为 (i) 的最大体格之和。

    设下一个状态为 (T = (S mid (1 << j - 1)))

    转移方程为:

    [f[T][j] = f[S][i] + dis[i][j] ]

    同时记录一个最大体格之和:

    [g[T][j] = max { g[S][i] + w[i][j] } ]

    其中 (dis[i][j], w[i][j]) 分别表示第 (i) 个菜店到第 (j) 个菜店的距离和最大体格之和。

    最后统计一下最优解即可。

    时间复杂度为 (mathcal O(nm + nms + pnm + 2^p p^2))

    /*
    Work by: Suzt_ilymtics
    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 = 2e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    int dx[] = {0, 0, 1, -1};
    int dy[] = {1, -1, 0, 0};
    
    struct node {
        int x, y;
    }b[18];
    
    int n, m, s, p, sc = 0;
    int a[330][330];
    int dis[18][18], w[18][18], val[330][330];
    int Dis[330][330], Val[330][330];
    int f[MAXN][18], g[MAXN][18];
    bool vis[330][330], flag[330][330];
    
    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 Calc(int sx, int sy, int ex, int ey) { return a[ex][ey] + a[sx - 1][sy - 1] - a[sx - 1][ey] - a[ex][sy - 1]; }
    bool Check(node v) { return v.x < 1 || v.y < 1 || v.x > n || v.y > m; }
    
    void bfs(int sx, int sy) {
        memset(Dis, 0x3f, sizeof Dis);
        memset(Val, 0, sizeof Val);
        memset(vis, false, sizeof vis);
        queue<node> q;
        q.push((node){sx, sy});
        Dis[sx][sy] = 0, vis[sx][sy] = true;
        while(!q.empty()) {
            node u = q.front(); q.pop();
            vis[u.x][u.y] = false;
            for(int i = 0; i < 4; ++i) {
                node v = (node){u.x + dx[i], u.y + dy[i]};
                if(Check(v) || flag[v.x][v.y]) continue;
                if(Dis[v.x][v.y] > Dis[u.x][u.y] + 1) {
                    Dis[v.x][v.y] = Dis[u.x][u.y] + 1;
                    Val[v.x][v.y] = Val[u.x][u.y] + val[v.x][v.y];
                    if(!vis[v.x][v.y]) q.push(v), vis[v.x][v.y] = true;
                } else if(Dis[v.x][v.y] == Dis[u.x][u.y] + 1) {
                    Val[v.x][v.y] = max(Val[v.x][v.y], Val[u.x][u.y] + val[v.x][v.y]);
                    if(!vis[v.x][v.y]) q.push(v), vis[v.x][v.y] = true;
                }
            }
        }
    }
    
    int main()
    {
    //    freopen("expand2.in","r",stdin);
    //    freopen("expand.out","w",stdout);
    	n = read(), m = read(), s = read();
    	for(int i = 1; i <= n; ++i) 
    	    for(int j = 1; j <= m; ++j) 
    	        a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + (flag[i][j] = read());
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                for(int k = 0; k <= s; ++k) {
                    int sx = i - k, sy = j - k, ex = i + k, ey = j + k;
                    if(sx < 1 || sy < 1 || ex > n || ey > m) break;
                    int sum = Calc(sx, sy, ex, ey);
                    if(sum) break;
                    else val[i][j] = k;
                }
            }
        }
        b[++sc].x = read() + 1, b[sc].y = read() + 1, p = read();
        for(int i = 1; i <= p; ++i) b[++sc].x = read() + 1, b[sc].y = read() + 1;
        for(int i = 1; i <= sc; ++i) {
            bfs(b[i].x, b[i].y);
            for(int j = 1; j <= sc; ++j) {
                dis[i][j] = Dis[b[j].x][b[j].y];
                w[i][j] = Val[b[j].x][b[j].y];
            }
        }
        memset(f, 0x3f, sizeof f);
        f[1][1] = 0, g[1][1] = val[b[1].x][b[1].y];
        for(int S = 0; S < (1 << sc); ++S) {
            for(int i = 1; i <= sc; ++i) {
                if(!(S & (1 << i - 1))) continue;
                for(int j = 1; j <= sc; ++j) {
                    if(S & (1 << j - 1)) continue;
                    int T = (S | (1 << j - 1));
                    if(f[T][j] > f[S][i] + dis[i][j]) {
                        f[T][j] = f[S][i] + dis[i][j];
                        g[T][j] = g[S][i] + w[i][j];
                    } else if(f[T][j] == f[S][i] + dis[i][j]) {
                        g[T][j] = max(g[T][j], g[S][i] + w[i][j]);
                    }
                }
            }
        }
        int ans = 0x3f3f3f3f, res = 0, S = (1 << sc) - 1;
        for(int j = 1; j <= sc; ++j) {
            if(ans > f[S][j]) ans = f[S][j], res = g[S][j];
            else if(ans == f[S][j]) res = max(res, g[S][j]);
        }
        printf("%d %d
    ", ans, res);
        return 0;
    }
    

    C birthday

    (10\%) 部分分,啥都不用干,直接 return 0

    对于 (r-l+1) 的部分分,对于每个操作 (1) 可以 (3^n) 枚举所有情况。爆搜位运算均可。对于操作 (2) 可以暴力修改。

    但是这个出题人 tmd 没放这个部分分的数据啊!/fn

    考虑正解。

    (len = r - l + 1),可组成的值域范围为 ([len, len imes V])

    然后 (len) 个数可组成的数的数量为 (2^{len})

    所以当 (2^{len} > len imes V) 的时候就一定有解。

    解的 (len) 的最小整数解为 (14)

    所以当 (len ge 14) 是一定有解。

    考虑 (len < 13) 的情况怎么做,直接爆搜 (3^{len}) 是承受不了的。

    但是这里有一句很著名的话:

    Stop learning useless algorithms, go and solve some problems, learn how to use binary search.

    所以分开搜就可以了。在搜后半部分的时候也要判断能不能和前半部分匹配,时间复杂度还是 (3^7) 级别,可以通过。

    /*
    Work by: Suzt_ilymtics
    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 = 1e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    int n, m, V, opt, l, r, mid;
    int a[MAXN], stc[MAXN], sc = 0;
    int f[MAXN][22]; 
    bool flag[MAXN], Flag = false;
    
    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;
    }
    
    namespace Seg {
        #define lson i << 1 
        #define rson i << 1 | 1
        int lazy[MAXN << 2];
        void Push_up(int i) { ; }
        void Push_down(int i) {
            if(lazy[i] == 0) return ;
            lazy[lson] = lazy[i] + lazy[lson];
            lazy[rson] = lazy[i] + lazy[rson];
            lazy[i] = 0;
        }
        void Modify(int i, int l, int r, int L, int R) {
            if(L <= l && r <= R) return (void)(lazy[i] = lazy[i] + 1);
            Push_down(i);
            int mid = (l + r) >> 1;
            if(mid >= L) Modify(lson, l, mid, L, R);
            if(mid < R) Modify(rson, mid + 1, r, L, R);
            Push_up(i); 
        }
        void Query(int i, int l, int r, int L, int R) {
            if(l == r) {
                for(int j = 0; j <= 20; ++j) if(lazy[i] & (1 << j)) a[l] = f[a[l]][j];
                return (void)(lazy[i] = 0);
            }
            Push_down(i);
            int mid = (l + r) >> 1;
            if(mid >= L) Query(lson, l, mid, L, R);
            if(mid < R) Query(rson, mid + 1, r, L, R);
        }
    }
    
    void Init() {
        for(int i = 0; i < V; ++i) f[i][0] = i * i * i % V; 
        for(int i = 1; i <= 20; ++i) 
            for(int j = 0; j < V; ++j) 
                f[j][i] = f[f[j][i - 1]][i - 1];
    }
    
    void dfsl(int pos, int dis, bool k) {
        if(Flag) return ;
        if(pos == mid + 1) {
            if(!k) return ;
            if(!dis) Flag = true;
            else if(dis >= 0 && !flag[dis]) flag[dis] = true, stc[++sc] = dis;
            return ;
        }
        dfsl(pos + 1, dis, k);
        dfsl(pos + 1, dis + a[pos] + 1, true);
        dfsl(pos + 1, dis - a[pos] - 1, true);
    }
    
    void dfsr(int pos, int dis, bool k) {
        if(Flag) return ;
        if(pos == r + 1) {
            if(!k) return ;
            if(!dis) Flag = true;
            else if(dis >= 0 && flag[dis]) Flag = true;
            return ;
        }
        dfsr(pos + 1, dis, k);
        dfsr(pos + 1, dis + a[pos] + 1, true);
        dfsr(pos + 1, dis - a[pos] - 1, true);
    }
    
    int main()
    {
    	n = read(), m = read(), V = read();
    	Init();
    	for(int i = 1; i <= n; ++i) a[i] = read();
        for(int i = 1; i <= m; ++i) {
            opt = read(), l = read(), r = read();
            if(opt == 2) {
                Seg::Modify(1, 1, n, l, r);
            } else {
                if(r - l + 1 >= 14) { puts("Yes"); continue; }
                Seg::Query(1, 1, n, l, r);
                mid = (l + r) >> 1; 
                sc = 0, Flag = false;
                dfsl(l, 0, false), dfsr(mid + 1, 0, false);
                while(sc) flag[stc[sc--]] = false;
                Flag ? puts("Yes") : puts("No");
            }
        }
        return 0;
    }
    /*
    
    20 20 152
    3 26 133 54 79 81 72 109 66 91 82 100 35 23 104 17 51 114 12 58
    2 1 17
    2 6 12
    1 1 12
    2 3 5
    2 11 11
    2 7 19
    2 6 15
    1 5 12
    1 1 9
    1 10 19
    2 3 19
    2 6 20
    2 1 13
    2 1 15
    2 1 9
    1 1 1
    2 1 7
    2 7 19
    2 6 19
    2 3 6
    
    */
    
  • 相关阅读:
    输入汉字转拼音
    DBGridEh(RestoreGridLayoutIni)用法
    当选中节点的同时选中父节点
    implsments
    HTML中的post和get
    SmartUpload中文乱码
    调查平台,考试系统类型的数据收集型项目
    final
    职业生涯中12个最致命的想法
    abstract
  • 原文地址:https://www.cnblogs.com/Silymtics/p/test-GRYZ20211102.html
Copyright © 2020-2023  润新知