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

*/
原文地址:https://www.cnblogs.com/Silymtics/p/test-GRYZ20211102.html