Loading

AtCoder Beginner Contest 298




B - Coloring Matrix

题目大意

给定两个由0 1组成的矩阵A, B; 我们可以让矩阵A顺时针旋转, 问是否可以让A中 1 的坐标放在B中也是 1 ;

解题思路

暴力转四次检查即可

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e2 + 10, mod = 998244353;
int n, m;
int a[N][N], b[N][N];
vector<PII> v;
map<PII, int> mp;
void change () {
	for (int i = 0; i < v.size(); i++) {
		int x = v[i].second, y = n-v[i].first+1;
		v[i] = { x,y };
	}
}
signed main(){
	cin >> n;
	for (int i = 1; i <= 2 * n; i++) {
		for (int j = 1; j <= n; j++) {
			if (i <= n) {
				cin >> a[i][j];
				if (a[i][j] == 1) v.push_back({ i,j });
			}
			else {
				cin >> b[i-n][j];
				if (b[i-n][j] == 1) mp[{i-n, j}]++;
			}
		}
	}
	for (int i = 1; i <= 4; i++) {
		bool f = true;
		for (int j = 0; j < v.size(); j++) {
			int x = v[j].first, y = v[j].second;
			if (mp[{x, y}] == 0) {
				f = false;
				break;
			}
		}
		if(!f) change();
		else {
			cout << "Yes" << endl;
			return 0;
		}
	}
	cout << "No" << endl;
	return 0;
}




C - Cards Query Problem

题目大意

给定n个有编号箱子和若干写有数字的卡片, 现有m次操作, " 1 a b "表示把写有a数字的卡片放进b箱子里; " 2 a "表示把a箱子的卡片按升序输出, 若有多个相同数字的也要输出多次; " 3 a "表示把所有含a数字卡片的箱子的编号按升序输出;

解题思路

用map模拟一下就行

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10, mod = 998244353;
int n, m;
map<int, multiset<int>> mims;
map<int, set<int>> mis;
signed main(){
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int x, a, b;
		cin >> x;
		if (x == 1) {
			cin >> a >> b;
			mims[b].insert(a);
			mis[a].insert(b);
		}
		else if (x == 2) {
			cin >> a;
			auto s = mims[a];
			for (int t : s) {
				cout << t << ' ';
			}
			cout << endl;
		}
		else {
			cin >> a;
			auto s = mis[a];
			for (int t : s) {
				cout << t << ' ';
			}
			cout << endl;
		}
	}
	return 0;
}




D - Writing a Numeral

题目大意

现在有一个序列, 初始情况下为 1, 现在有3种操作: " 1 a "将数字a插入到序列最后; " 2 "删除序列开头的数字; " 3 "输出当前序列所表示的十进制数字对998244353取模后的结果;

解题思路

也是一个模拟题, 根据尾进头出的特点可以用队列; 但是就取模操作卡了我很久, 所以要养成习惯: 遇到减法运算时要先加上mod后再对整体取模; 两数相加后取模和两数取模后相加结果没有区别, 但是为了防止中间量过大, 所以一般采取后者; 为了防止处理10的幂数时会爆, 所以需要手写快速幂, 边处理边取模;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 3e5 + 10, mod = 998244353;
int n, m, res;
queue<int> q;
int qmi(int a, int b) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}
signed main(){
    int t;
    cin >> t;
    q.push(1);
    res = 1;
    while(t--){
        int a, b;
        cin >> a;
        if(a == 1){
            cin >> b;
            q.push(b);
            res = (res * 10 % mod + b) % mod;
        }
        else if(a == 2){
            int x = q.front();
            q.pop();
            res = (res - x * qmi(10, q.size()) % mod + mod) % mod;
        }
        else if(a == 3){
            cout << res << endl;
        }
    }
    return 0;
}




E - Unfair Sugoroku

题目大意

小莫和安姐玩一个走格子游戏, 小莫起始在a点, 安姐起始在b点; 他们各有一个骰子, 小莫的骰子点数是1~c, 而安姐是1~d, 摇到哪个点数就走几步, 小莫先手, 看谁先到达n点; 问小莫赢的概率, 对mod取模;

解题思路

这个题和abc300的e题有些相似; 我看题解称之为概率dp;
状态表示 dp[a][b][1/0] 表示小莫走到a点, 安姐走到b点, 且上一步是小莫/安姐先手; 首先先用两层循环遍历a和b, 小莫可能达到的点数是(a + 1) ~ (n + c - 1), 安姐是b ~ (n - 1); 因为我们计算的是小莫胜利的情况, 所以安姐不能到n; 注意当a大于n时, 在状态计算时要算到n里面; 下面说一下状态计算:
小莫先手时: dp[min(i, n)][j][1] += dp[i - k][j][0] * qmi(c, mod - 2) % mod; 其中k需要遍历1 ~ c, 这是一个累加的过程; 注意当i - k < a 就不用加这一项了; 同理安姐先手时: dp[i][j][0] = dp[i][j - k][1] * qmi(d, mod - 2) % mod 限制条件也存在; 最后再把dp[n][j][1]累加一下就行, i是b~n-1; 注意是累加, 一开始脑子有点乱写出最大值了;
注意分数取模用费马小定理: a / b % mod = a * (b对mod的逆元);

神秘代码

##include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 3e5 + 10, mod = 998244353;
int n, m, res;
int dp[210][210][2];
int qmi(int a, int b){
    int res = 1;
    while(b){
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
signed main(){
    int a, b, c, d;
    cin >> n >> a >> b >> c >> d;
    dp[a][b][0] = 1;
    for(int i = a +1; i < n + c; i++){
        for(int j = b; j < n; j++){
            for(int k = 1; k <= c; k++){
                if(i - k < a) break;
                dp[min(i, n)][j][1] = (dp[min(i, n)][j][1] + dp[i - k][j][0] * qmi(c, mod - 2) % mod) % mod;
            }
            if(i < n){
                for(int k = 1; k <= d; k++){
                    if(j - k < b) break;
                    dp[i][j][0] = (dp[i][j][0] + dp[i][j - k][1] * qmi(d, mod - 2) % mod) % mod;
                }
            }
           
        }
    }
    for(int j = b; j < n; j++){
        res = (res + dp[n][j][1]) % mod;
    }
    cout << res;
    return 0;
}




F - Rook Score

难度: ⭐⭐⭐

题目大意

现有一个二维矩阵, 给出n个点的行和列以及该位置的值是多少, 这n个点以外的点的值都是0; 现在让你选择一个点P(r,c), 要求该点所在的行的值总和加上列的值总和最大; 相交的点只算一次;

解题思路

本题虽然是1e5的数量级, 但是题目给了3秒, 没想到剪枝的二重循环竟然能过; 把所有给出的点先存起来, 同时计算出提到的行和列的值总和, 然后各自从大到小排序; 我们遍历行和列, 如果x行和y列的交点是0, 就可以结束第二重循环了, 因为我们是从大到小排序的, 后面不会有更大的; 通过这样剪枝可以ac;
注意vector要用pair类型把行/列和其对应的值都存下来; 因为map的查询也是O(logn)的复杂度, 不如vector的O(1)快, 否则也会TLE;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10;
typedef pair<int, int> PII;
int n, m, res;
map<PII, int> mp;
map<int, int> rs, cs;
vector<PII> rsv, csv;
bool cmp(PII a, PII b) {
    return a.second > b.second;
}
signed main() {
    IOS;
    cin >> n;
    int rmax = 0, cmax = 0;
    for (int i = 1; i <= n; i++) {
        int r, c, x;
        cin >> r >> c >> x;
        mp[{r, c}] = x;
        cs[c] += x;
        rs[r] += x;
    }
    for (auto t : rs) rsv.push_back(t);
    for (auto t : cs) csv.push_back(t);
    sort(rsv.begin(), rsv.end(), cmp);
    sort(csv.begin(), csv.end(), cmp);
    for (auto x : rsv) {
        for (auto y : csv) {
            if (mp[{x.first, y.first}]) {
                res = max(res, x.second + y.second - mp[{x.first, y.first}]);
            }
            else {
                res = max(res, x.second + y.second);
                break;
            }
        }
    }
    cout << res;
    return 0;
}
posted @ 2023-06-28 08:14  mostimali  阅读(7)  评论(0编辑  收藏  举报