A.Anyway Takahashi
题意
签到,输出 ( a + b ) ∗ ( c − d ) (a+b)*(c-d) (a+b)∗(c−d)
代码
#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 lb−mid中的棋子小于对应的行数或者列数,那么说明棋子应该放在 l b − m i d lb-mid lb−mid中。
题意
#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 n∗m 的棋盘,每个格子 ( x , y ) (x,y) (x,y)的价值为 x ∗ m + y x*m+y x∗m+y,特别的是若 x + y x+y x+y 为奇数,那么该格子的价值为 0。求左上角 ( A , C ) (A,C) (A,C),右下角 ( B , D ) (B,D) (B,D)的矩阵的价值。
题解
首先我们可以考虑通过求二维前缀和的方式得到结果会更为简便。
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;
}