GRYZ20211028模拟赛解题报告


目录
  • 写在前面
  • T1
  • T2
  • T3
    • 20pts Code
    • 50pts Code

写在前面

期望得分:\(100+100+30 \sim 60 = 230 \sim 260pts\)
实际得分:\(90 + 96 + 50 = 236pts\)

(第二题十二个测试点,每个测试点 \(8pts\)

今天轮到三区出题了,龙又搬了他那不知几年前搞的题。

也可能是感觉我们前两天考的太烂于是换了套简单的(((

T1

你发现出现次数 \(\ge \frac{n+1}{2}\) 的数不会太多,然后你直接离散化统计出现次数找到那几个出现次数 \(\ge \frac{n+1}{2}\) 的数,暴力判断需要翻转几次,对次数取 \(\min\) 即可。

为什么挂了 10pts ?因为他这个点卡快读 /fn/fn

/*
Work by: Suzt_ilymtics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include
#include
#include
#include
#include
#include
#define LL long long
#define orz cout<<"lkp AK IOI!"<= (n + 1) / 2) {
            int res = 0;
            for(int j = 1; j <= n; ++j) {
                if(a[j].x == i) {
                    res ++;
                }
            }
            ans = min(ans, max((n + 1) / 2 - res, 0));
        }
    }
    if(ans == INF) puts("Impossible");
    else printf("%d\n", ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T2

首先你要知道这个交换相邻元素使序列排好序是让你求逆序对。

然后你考虑确定出这几个子串的大小关系。

考虑自定义一个 cmp 直接排序,因为空间关系,我们要对起始位置排序而不是把每个子串列出来排序。

时间复杂度 \(\mathcal O(nm \log n)\)

考虑如何优化。

发现瓶颈在于比较两个串的大小关系,然后你考虑 Hash + ST 表,然后你就可以在 \(\log m\) 的时间内比较两个串的大小关系了。

时间复杂度 \(\mathcal O(n \log m \log n)\)

ST 表几乎没用过,但它并没有让我调太多时间,这很好。

/*
Work by: Suzt_ilymtics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include
#include
#include
#include
#include
#include
#define int long long
#define orz cout<<"lkp AK IOI!"<= 0; --j) {
        if(x + (1 << j) > n || y + (1 << j) > n) continue;
        if(st[x + len][j] == st[y + len][j]) {
            len = len + (1 << j);
        }
    }
    if(len >= m) return false;
    for(int i = len + 1; i <= m; ++i) {
        if(s[x + i - 1] < s[y + i - 1]) return true;
        if(s[x + i - 1] > s[y + i - 1]) return false; 
    }
    return false;
}

bool Check(int l, int r) {
    int len = 0;
    for(int j = 16; j >= 0; --j) {
        if(l + (1 << j) > n || r + (1 << j) > n) continue;
        if(st[l + len][j] == st[r + len][j]) {
            len = len + (1 << j);
        }
    }
    if(len >= m) return true;
    else return false;
}

signed main()
{
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
	n = read(), m = read();
	cin >> s + 1;
	Pow[0] = 1;
    for(int i = 1; i <= n + m; ++i)  Pow[i] = Pow[i - 1] * base % mod;
	for(int i = 1; i <= m; ++i) s[n + i] = '1';
	s[n + m + 1] = '\0';
	for(int i = 1; i <= n; ++i) {
	    st[i][0] = s[i];
    }
    for(int i = 1; i <= 16; ++i) {
        for(int j = 1; j <= n; ++j) {
            st[j][i] = st[j][i - 1] * Pow[(1 << i - 1)] % mod + st[j + (1 << i - 1)][i - 1];
            st[j][i] %= mod;
//            cout<= 1; --i) {
	    int res = Bit::Query(c[i] - 1);
	    ans = ans + res;
	    Bit::Modify(c[i], 1);
    }
    printf("%lld\n", ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T3

用 set 维护每一块巧克力然后爆搜切哪 \(k-1\) 刀。

时间复杂度 \(\mathcal O(\text{巨大})\)

反正大样例跑了两个半小时都没跑完。

实测只能过 20 pts ?还有两个点 WA 掉了。

然后你又想了另外一种方法,你先预处理出每个 \(a_i\) 能被那些矩形所拼。

然后你 dfs 每个 \(a_i\) 用哪个矩形,这样就做有 50pts 的好成绩。还是有两个点 WA 掉了,很奇怪(和上面 WA 掉的两个点不一样)

正解是记忆化搜索,设 \(f[sx][sy][ex][ey][S]\) 表示 \((sx,sy) - (ex, ey)\) 这块矩形能否组成的一部分 \(a_i\) 的组成的集合 \(S\)

20pts Code

/*
Work by: Suzt_ilymtics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define orz cout<<"lkp AK IOI!"< S;

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 lx, int ly, int rx, int ry) {
    return s[rx][ry] - s[lx - 1][ry] - s[rx][ly - 1] + s[lx - 1][ly - 1];
}

void dfs(int pos) {
    if(pos == K) {
//        cout<::iterator it = S.begin(); it != S.end(); ++it) {
            int x = Calc(it->lx, it->ly, it->rx, it->ry);
            if(!flag[x] && vis[x]) flag[x] = true, res++;
        }
        for(multiset::iterator it = S.begin(); it != S.end(); ++it) {
            int x = Calc(it->lx, it->ly, it->rx, it->ry);
            flag[x] = false;
        }
        if(res == K) Flag = true;
        return ;
    }
    multiset E = S;
    for(multiset::iterator it = E.begin(); it != E.end(); ++it) {
        node x = *it;
        S.erase(x);
        for(int i = x.lx; i < x.rx; ++i) {
            S.insert((node){x.lx, x.ly, i, x.ry});
            S.insert((node){i + 1, x.ly, x.rx, x.ry});
            dfs(pos + 1);
            S.erase((node){x.lx, x.ly, i, x.ry});
            S.erase((node){i + 1, x.ly, x.rx, x.ry});
            if(Flag) return ;
        }
        for(int i = x.ly; i < x.ry; ++i) {
            S.insert((node){x.lx, x.ly, x.rx, i});
            S.insert((node){x.lx, i + 1, x.rx, x.ry});
            dfs(pos + 1);
            S.erase((node){x.lx, x.ly, x.rx, i});
            S.erase((node){x.lx, i + 1, x.rx, x.ry});
            if(Flag) return ;
        }
        S.insert(x);
    }
}

int main()
{
    freopen("chocolate.in","r",stdin);
    freopen("chocolate.out","w",stdout);
	int T = read();
	while(T--) {
	    S.clear(); Flag = false;
	    bool fjh = false;
	    n = read(), m = read(), K = read();
	    for(int i = 1; i <= n; ++i) {
	        for(int j = 1; j <= m; ++j) {
	            a[i][j] = read();
	            if(a[i][j] != 1) fjh = true;
	            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
            }
        }
        memset(vis, false, sizeof vis);
        for(int i = 1; i <= K; ++i) b[i] = read(), vis[b[i]] = true;
        int sum = 0;
        for(int i = 1; i <= K; ++i) sum = sum + b[i];
        if(n == 1 && !fjh) {
            if(sum == m) puts("yes");
            else puts("no");
            continue;
        }
        if(sum != s[n][m]) {
            puts("no");
            continue;
        }
        S.insert((node){1, 1, n, m});
        cnt[s[n][m]]++;
        dfs(1);
        if(Flag) puts("yes");
        else puts("no");
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

50pts Code

/*
Work by: Suzt_ilymtics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include
#include
#include
#include
#include
#include
#define LL long long
#define orz cout<<"lkp AK IOI!"< V[20];

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 lx, int ly, int rx, int ry) {
    return s[rx][ry] - s[lx - 1][ry] - s[rx][ly - 1] + s[lx - 1][ly - 1];
}

void dfs(int pos) {
    if(pos == K + 1) {
        Flag = true;
        return ;
    }
    for(int i = 0, M = V[pos].size(); i < M; ++i) {
        bool flag = false;
        int sx = V[pos][i].sx, ex = V[pos][i].ex, sy = V[pos][i].sy, ey = V[pos][i].ey;
        for(int j = sx; j <= ex; ++j) {
            for(int k = sy; k <= ey; ++k) {
                if(vis[j][k]) {
                    flag = true;
                    break;
                }
            }
            if(flag) break;
        }
        if(!flag) {
            for(int j = sx; j <= ex; ++j) {
                for(int k = sy; k <= ey; ++k) {
                    vis[j][k] = true;
                }
            }    
            dfs(pos + 1);
            if(Flag) return ;
            for(int j = sx; j <= ex; ++j) {
                for(int k = sy; k <= ey; ++k) {
                    vis[j][k] = false;
                }
            }            
        } 
    }
}

int main()
{
    freopen("chocolate.in","r",stdin);
    freopen("chocolate.out","w",stdout);
	int T = read();
    while(T--) {
        n = read(), m = read(), K = read();
        bool fjh = false;
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j<= m; ++j) {
                a[i][j] = read();
                if(a[i][j] != 1) fjh = true;
                s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; 
            }
        }
        int sum = 0;
        for(int i = 1; i <= K; ++i) {
            b[i] = read();
            sum = sum + b[i];
            V[i].clear();
            for(int sx = 1; sx <= n; ++sx) {
                for(int sy = 1; sy <= m; ++sy) {
                    for(int ex = sx; ex <= n; ++ex) {
                        for(int ey = sy; ey <= m; ++ey) {
                            int x = Calc(sx, sy, ex, ey);
                            if(x == b[i]) V[i].push_back((node){sx, sy, ex, ey});
                        }
                    }
                }
            }
        }
        if(n == 1 && !fjh) {
            if(sum == s[n][m]) puts("yes");
            else puts("no");
            continue;
        }
        if(sum < s[n][m]) {
            puts("no");
            continue;
        }
        Flag = false;
        memset(vis, false, sizeof vis);
        dfs(1);
        if(!Flag) puts("no");
        else puts("yes");
    } 
    fclose(stdin);
    fclose(stdout);
    return 0;
}

其实我觉得两个部分分代码放着没什么必要,就是恶心恶心人(((

相关