7.27模考总结.fjx

本周进行了标准OI基础组模考测试
得分情况

题目名称 做法 预计得分 实际得分
A 默认价格 哈希表 100 100
B 贪吃蛇迷宫 BFS搜索 100 100
C 保持距离 DFS搜索、数学优化 20 30
D 单元格 数论 10 20
E 补充括号 区间DP 10 10

点开第一题,一开始有点不懂题目什么意思,后来懂了,用一个 map 存储价格即可
用时10分钟AC
第二题,是一个搜索题目,对于我来说搜索就是语法题,所以我很快写了一个 BFS 模版出来,一遍AC,耗时10分钟
接着看第三题,开始加难度了,赛中我有一个离谱的思路,就是先得出每次+10的序列,我们每次可以把一个数+1,这样后面的数都要+1(类似差分)
而且保证最后一个元素最大,而且每次不管在哪里做差分,他肯定会+1,所以我们只需要维护这个值不超过 m 即可
我们就可以把 m - 序列最后的值 看做可以把一个数+1的总次数,然后用搜索看一下用哪几个来++
但是我写了20分钟仍然阳历不过,一筹莫展,我只好换一个思路,就是直接每次枚举+几,别管什么差分了,直接爆搜!于是我吭哧吭哧写了2分钟爆搜,TLE30分,甚好甚好!
接下来看第四题,嗯,也是不会,思考了30分钟没有任何头绪
于是我没办法,为了思考下一题直接写了一个华丽的6重循环,TLE20分
接下来第5题,我还以为是括号匹配呢,结果写完栈的括号匹配不对,发现原来是区间DP,于是我吭哧吭哧写了一个区间DP模版,结果发现样例没过,然后我调试了好久也没调出来,只好输出一个0骗了10分
赛后我居然发现,我把判断的 “或者” 写错了,写成了 “并且”,把那个错误改过来就AC了

总结:
嗯,感觉表现其实不错,就是代码有一点小问题,写代码的时候要仔细一点,如果够仔细那么就能A掉最后一题

题目讲解

局部截取_20250727_160555
局部截取_20250727_160609
局部截取_20250727_193903

非常简单,用 map 哈希表存储每一个颜色的寿司的价格,随后枚举每一个吃了的寿司看一下价格,如果没有标注就加上 P_0 即可
code

map <string, int> mp;
    cin >> p[0];
    for (int i = 1 ; i <= m ; i++) {
        cin >> p[i];
        mp[d[i]] = p[i];
    }
    ll res = 0;
    for (int i = 1 ; i <= n ; i++) {
        if (!mp[c[i]]) {
            res += p[0];
        } else {
            res += mp[c[i]];
        }
    }
    cout << res << endl;

局部截取_20250727_161322
局部截取_20250727_161338
局部截取_20250727_161349
局部截取_20250727_161358

非常简单,直接用BFS搜索就可以,至于那个 snuke,判断一下就好啦!

code

char mp[510][510];
bool vis[510][510];
struct node {
    int x, y, id;
};
string s = "snuke";
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, -1, 0, 1};
void bfs() {
    queue<node> q;
    q.push({1, 1, 0});
    vis[1][1] = true;
    while (!q.empty()) {
        node now = q.front();
        q.pop();
        if (now.x == n && now.y == m) {
            cout << "Yes" << endl;
            return;
        }
        for (int i = 0; i < 4; i++) {
            int nx = now.x + dx[i];
            int ny = now.y + dy[i];
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && !vis[nx][ny] && mp[nx][ny] == s[(now.id + 1) % 5]) {
                vis[nx][ny] = true;
                q.push({nx, ny, (now.id + 1) % 5});
            }
        }
    }
    cout << "No" << endl;
}

局部截取_20250727_161703
局部截取_20250727_161718
局部截取_20250727_161753

搜索加一点数论
首先写一个暴搜,随后我们分析一下:

  • 题目的元素是十进制
  • 而且两个相邻的数的差值最小是10

我们可以推导出,其实 m 不需要那么多数位,只需要1位(或10)
所以出入完 m 的时候 m=(m-1) mod 10+1 ,然后就——完结散花

code

vector<ll> v;
vector<vector<ll> > res;
inline void dfs(int x, int len) {
    if (len > n) {
        res.push_back(v);
        // cout << "todo" << endl;
        return;
    }
    for (int i = x; i <= m; i++) {
        v.push_back(i);
        // cout << "todo";
        dfs(i, len + 1);
        v.pop_back();
    }
}
ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    m = (m - 1) % 10 + 1;
    dfs(1, 1);
    cout << res.size() << endl;

局部截取_20250727_162620
局部截取_20250727_162630

想一想,如果我们暴力枚举每个点,时间复杂度是 O(n^6) ,绝对会超时
我们不妨换一个思路:
3个点一定能形成一个矩形,这个矩形周长就是他们的总共费用
示例:
局部截取_20250727_200139

所以我们枚举每一个矩形,看一下有多少个这样子的矩形(前提是矩形周长复合标准),记录一个值 k
看一看这个矩形得边上选3个不同位置的点的方案数,记录到 p
最后 ans=(ans+p \times k) mod 1000000007
而我们通过简单的推算,发现
k=(n-i+1)\times(m-j+1)
p=(i-2)\times (j-2)\times 6
所以这题就做完了
code

for (int i = 3 ; i <= n ; i++) {
	for (int j = 3 ; j <= m ; j++) {
		int c = i * 2 + j * 2 - 4;
		if (c <= maxt && c >= mint) {
			int k = (n - i + 1) * (m - j + 1);
			int p = (i - 2) * (j - 2) * 6ll;
			ans = (ans + p * k) % mod;
		}
	}
}

局部截取_20250727_164326
局部截取_20250727_164337
局部截取_20250727_164348

区间DP模版题

首先我们想,不管这个括号时什么,单独一个括号肯定是不合法的,需要添加一个匹配的括号
所以所有的 dp[i][i]=1

其次,我们发现,在某些情况下,一个区间的两半加起来就是答案
比如序列[[[))),很明显dp[1][3] = dp[4][6] = 3,而dp[1][6] = dp[1][3] + dp[4][6] = 6
所以在选分割点的时候, dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]) 即所有情况都可能
但是有一种不是,比如[([])]dp[2][5]就不能用刚才的推到公式了
因为两边的括号相匹配,所以我们就视为其没有,那么长度就会莫名其妙少了2,所以我们要向外扩充各1格

code

for(int i = 0;i < n;i++) dp[i][i] = 1;
	for(int len = 2;len <= n;len++){
		for(int l = 0;l + len - 1 < n;l++){
			int r = l + len - 1;
			dp[l][r] = 0x3f3f3f3f;
			if((s[l] == '(' && s[r] == ')') || (s[l] == '[' && s[r] == ']')){
				dp[l][r] = dp[l + 1][r - 1];
			}
			for(int k = l;k < r;k++){
				dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]);
			}
		}
	}
	cout << dp[0][n - 1];

你的表格下面那个位置有点问题
image

1 个赞

知道啦喵