UNICORN Programming Contest 2022(AtCoder Beginner Contest 269)

A.Anyway Takahashi

题意

签到,输出 ( a + b ) ∗ ( c − d ) (a+b)*(c-d) (a+b)(cd)

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll a, b, c, d;

int main() {
	cin >> a >> b >> c >> d;
	cout << (a + b) * (c - d) << "\n";
	cout << "Takahashi";
	return 0;
}

B.Rectangle Detection

题意

矩阵方块,找出 # 方块,输出左上角和右下角

题解

遍历,输出第一个 # 的坐标和最后一个 # 坐标即可

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

char mp[20][20];

int main() {
	int a = 20, b = 0, c = 20, d = 0;
	for (int i = 1; i <= 10; i++) {
		for (int j = 1; j <= 10; j++) {
			cin >> mp[i][j];
			if (mp[i][j] == '#') {
				a = min(a, i), b = max(b, i);
				c = min(c, j), d = max(d, j);
			}
		}
	}
	cout << a << " " << b << "\n";
	cout << c << " " << d << "\n";
	return 0;
}

C.Submask

题意

对于一个整数 n n n,写成二进制后为 1 的那一位可以变成 0,输出所有可能变成的数。

题解

由于最多只有15位为1,预处理后,二进制枚举即可

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll n;
ll pre[100];

int main() {
	cin >> n;
	ll p = 1, num = 0;
	for (int i = 0; i <= 60; i++) {
		if ((n >> i) & 1) {
			pre[num++] = p;
		}
		p *= 2;
	}
	for (int i = 0; i < (1 << num); i++) {
		ll res = 0, tmp = i;
		for (int j = 0; j < num; j++) {
			if ((tmp >> j) & 1)res += pre[j];
		}
		cout << res << "\n";
	}
	return 0;
}

D.Do use hexagon grid

题意

蜂巢状网格,即六种移动,其中有部分网格被染成黑色,输出被染色的网格被分成的块数,边相连为一块。

题解

原来的写法是直接BFS,但是由于网格是2000 X 2000,并且有负数,需要用map进行访问标记,但是带log会TLE。

正确做法是给每个点按输入顺序标记,由于只有1000个点,可以用并查集合并方块,最后检查并查集中有多少个集合,就是最后的答案。

代码

#include<bits/stdc++.h>

#define ll long long
using namespace std;
typedef pair<int, int> P;

int n;
vector<P> vec;
map<P, int> mp;
int dx[10] = {0, 1, 1, 0, -1, -1}, dy[10] = {1, 1, 0, -1, -1, 0};
int par[1010];

int find(int x) { return x == par[x] ? x : par[x] = find(par[x]); }

void merge(int a, int b) {
    int x = find(a), y = find(b);
    if (x == y)return;
    par[x] = y;
}


int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin >> n;
    for (int i = 0; i < n; i++) {
        int x, y;
        cin >> x >> y;
        vec.push_back({x, y});
        mp[{x, y}] = i + 1;
        par[i + 1] = i + 1;
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < 6; k++) {
                if (vec[i].first - vec[j].first == dx[k] && vec[i].second - vec[j].second == dy[k]) {
                    merge(i + 1, j + 1);

                }
            }
        }
    }
    set<int> st;
    for (int i = 1; i <= n; i++) {
        st.insert(find(i));
    }
    cout << st.size();


    return 0;
}

E.Last Rook

题意

交互题,在棋盘中,保证每行每列都只有一个棋子,但还有一个棋子没有放。最多可以询问20次,在某个矩阵内有几个棋子,输出最后一个棋子的位置。

题解

由于棋盘只有1E3*1E3,可以分别二分行和列的位置。若 l b − m i d lb-mid lbmid中的棋子小于对应的行数或者列数,那么说明棋子应该放在 l b − m i d lb-mid lbmid中。

题意

#include<bits/stdc++.h>

#define ll long long
using namespace std;

int ask(int a, int b, int c, int d) {
    cout << "?" << " " << a << " " << b << " " << c << " " << d << "\n";
    int res;
    cin >> res;
    return res;
}

int n;

int main() {
    cin >> n;
    int x, y;
    int lb = 1, rb = n;
    while (lb < rb) {
        int mid = (lb + rb) / 2;
        if (ask(lb, mid, 1, n) < mid - lb + 1)rb = mid;
        else lb = mid + 1;
    }
    x = rb;
    lb = 1, rb = n;
    while (lb < rb) {
        int mid = (lb + rb) / 2;
        if (ask(1, n, lb, mid) < mid - lb + 1)rb = mid;
        else lb = mid + 1;
    }
    y = rb;
    cout << "! " << x << " " << y << "\n";


    return 0;
}

F.Numbered Checker

题意

有一个 n ∗ m n * m nm 的棋盘,每个格子 ( x , y ) (x,y) (x,y)的价值为 x ∗ m + y x*m+y xm+y,特别的是若 x + y x+y x+y 为奇数,那么该格子的价值为 0。求左上角 ( A , C ) (A,C) (A,C),右下角 ( B , D ) (B,D) (B,D)的矩阵的价值。

题解

81d92debe7aa949266f3a00cff13b513.png

首先我们可以考虑通过求二维前缀和的方式得到结果会更为简便。

a n s = a n s ( 1 , 1 , B , D ) + a n s ( 1 , 1 , A , C ) − a n s ( 1 , 1 , A , D ) − a n s ( 1 , 1 , B , C ) ans=ans(1,1,B,D)+ans(1,1,A,C)-ans(1,1,A,D)-ans(1,1,B,C) ans=ans(1,1,B,D)+ans(1,1,A,C)ans(1,1,A,D)ans(1,1,B,C)

那么接下来考虑如何求以 ( 1 , 1 ) (1,1) (1,1)为左上角的矩阵。

通过观察可以发现,只考虑奇数行时,同一行是一个含有(y+1)/2个元素的等差数列,同时以奇数行作为元素,也是一个等差数列。

同理,偶数行也满足。因此,分奇偶行分别用等差数列和公式求两次即可。

代码

#include<bits/stdc++.h>

#define ll long long
using namespace std;
const ll mod = 998244353;
const ll ni = 499122177;
int n, m;
int q;


ll sol(ll x, ll y) {
    ll pre1 = (y + 1) / 2, pre2 = y / 2;
    ll presum1 = pre1 * pre1 % mod;
    ll presum2 = (m + 2ll) * pre2 % mod + pre2 * (pre2 - 1) % mod;
    presum2 %= mod;
    ll num1 = (x + 1) / 2, num2 = x / 2;
    ll d1 = pre1 * 2 * m % mod, d2 = pre2 * 2 * m % mod;
    d1 %= mod, d2 %= mod;
    ll res = num1 * presum1 % mod + d1 * num1 % mod * (num1 - 1) % mod * ni % mod;
    res %= mod;
    res += num2 * presum2 % mod + d2 * num2 % mod * (num2 - 1) % mod * ni % mod;
    res %= mod;
    return res;
}

int main() {

    cin >> n >> m >> q;
    while (q--) {
        ll A, B, C, D;
        cin >> A >> B >> C >> D;
        A--, C--;
        ll ans = sol(B, D) - sol(A, D) + mod - sol(B, C) + mod + sol(A, C);
        ans %= mod;
        cout << ans << "\n";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值