C.图像存储
题目
数字图像是一个由“0”和“1”这两个元素组成的矩阵,除去边角上的元素,每个元素都有上下左右相邻的四个元素。再一个数字图像中,元素“0”代表空白,只有元素“1”所在的位置才有一个黑点。由此,一副黑白的图像得以显现。
为了能在更少的空间里存储更多的图像,一个可行的办法就是每种相同的黑块只保留一个,其他的地方只保留位置,这样便实现了压缩。查看时,只需将保留的黑块拓印到其它的位置,这样就实现了图像的复原。
可见,该技术的关键就是对不同的黑块进行记录。我们把由若干个相邻的“1”构成的区域定义为黑块,规定一个孤立的“1”也是一个黑块,黑块中“1”的个数为黑块的大小,通过上下左右平移可以实现重合并且等大的黑块为同一种黑块。现在你的任务是分别算出一个图像中黑块的个数和种数。
思路
dfs搜索黑块,对dfs搜索路径进行双哈希,素数最好开大点
Accepted code
/*
* @Autor: CofDoria
* @Date: 2021-01-10 21:48:38
* @LastEditTime: 2021-01-11 02:35:25
*/
// #include <bits/stdc++.h>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#define db double
#define ll long long
#define inf 0x3f3f3f3f
#define s(a, n) memset(a, n, sizeof(a))
#define debug(a) cout << '#' << a << '#' << endl
#define rep(l, a, b) for (register ll l = a; l < b; ++l)
#define per(l, a, b) for (register ll l = a; l >= b; --l)
#define _ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define _forit(i, c) \
for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); ++i)
bool fi = true;
const unsigned long long MOD = 1e9 + 7;
inline ll gcd(ll a, ll b) {
return (b == 0 ? a : gcd(b, a % b)); }
int mp[1005][1005];
int vis[1005][1005];
ll a[1000005];
int st[4][2] = {
{
0, 1}, {
0, -1}, {
1, 0}, {
-1, 0}};
int n, m;
int cnt = -1;
void dfs(int i, int j, int c) {
vis[i][j] = 1;
for (int x = 0; x < 4; x++) {
int ii = i + st[x][0];
int jj = j + st[x][1];
if (ii >= 0 && ii < n && jj >= 0 && jj < m && !vis[ii][jj] &&
mp[ii][jj]) {
a[c] = (a[c] * 131 % MOD + x*1007) % MOD;
dfs(ii, jj, c);
}
// 如果不明白这里为何要哈希 结合上图理解
a[c] = (a[c] * 131 % MOD + 31) % MOD;
}
return;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
while (~scanf("%d%d", &n, &m) && n && m) {
memset(a, 0, sizeof(a));
memset(vis, 0, sizeof(vis));
cnt = -1;
for (int i = 0; i < n; i++) {
char s[10005];
scanf("%s", s);
for (int j = 0; j < m; j++) {
mp[i][j] = s[j] - '0';
// vis[i][j] = 0;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (mp[i][j] == 1 && !vis[i][j]) dfs(i, j, ++cnt);
}
}
sort(a, a + cnt + 1);
printf("%d %d\n", cnt + 1, unique(a, a + cnt + 1) - a);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
D.坐标计数
题目
定义一个坐标变换,坐标 (x,y) 变换后变为 ( x ⊕ y x \oplus y x⊕y, ∣ x − y ∣ |x-y| ∣x−y∣)。
给定一片矩形区域,计算区域内有多少个整数点在经过有限次变换后变为 ( 0 , 0 ) (0,0) (0,0)。
思路
经过本地模拟打表后,发现所有点都可以在100次运算之内变为 ( 0 , 0 ) (0,0) (0,0)。注意点数需要开 l o n g l o n g long long longlong。
Accepted code
/*
* @Autor: CofDoria
* @Date: 2021-01-10 20:43:31
* @LastEditTime: 2021-01-10 21:18:46
*/
#include <bits/stdc++.h>
using namespace std;
#define db double
#define ll long long
#define inf 0x3f3f3f3f
#define s(a, n) memset(a, n, sizeof(a))
#define debug(a) cout << '#' << a << '#' << endl
#define rep(l, a, b) for (register ll l = a; l < b; ++l)
#define per(l, a, b) for (register ll l = a; l >= b; --l)
#define _ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define _forit(i, c) \
for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); ++i)
bool fi = true;
const unsigned long long MOD = 1e9 + 7;
inline ll gcd(ll a, ll b) {
return (b == 0 ? a : gcd(b, a % b)); }
bool f(int a, int b, int d) {
if (d > 100) return false;
if ((a ^ b) == 0 && abs(a - b) == 0)
return true;
else
return f((a ^ b), abs(a - b), d + 1);
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int t;
ll a1, a2, b1, b2;
cin >> t;
while (t--) {
cin >> a1 >> b1 >> a2 >> b2;
cout << (a2 - a1 + 1) * (b2 - b1 + 1) << endl;
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
G.简单题的逆袭
题目
给定x,y,找出满足方程 x k ≤ y x^k \le y xk≤y 的最大的k
思路
特判:当x小于2且x比y小时,k为无穷,当y为0时,k不存在;其他情况暴力求解,注意范围可能爆 l o n g l o n g long long longlong
Accepted code
/*
* @Autor: CofDoria
* @Date: 2021-01-10 20:18:40
* @LastEditTime: 2021-01-10 20:41:49
*/
#include <bits/stdc++.h>
using namespace std;
#define db double
#define ll long long
#define inf 0x3f3f3f3f
#define s(a, n) memset(a, n, sizeof(a))
#define debug(a) cout << '#' << a << '#' << endl
#define rep(l, a, b) for (register ll l = a; l < b; ++l)
#define per(l, a, b) for (register ll l = a; l >= b; --l)
#define _ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define _forit(i, c) \
for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); ++i)
bool fi = true;
const unsigned long long MOD = 1e9 + 7;
inline ll gcd(ll a, ll b) {
return (b == 0 ? a : gcd(b, a % b)); }
ll f(__int128_t a, __int128_t b) {
ll x = 0;
__int128_t m = a;
while (m <= b) {
x++;
m *= a;
}
return x;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
long long x, y;
int t;
cin >> t;
while (t--) {
cin >> x >> y;
if (x == 0 || (x == 1 && y) || y == 0) {
cout << -1 << endl;
} else {
cout << f(x, y) << endl;
}
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
H.对称之美
题目
给出n个字符串,从第1个字符串一直到第n个字符串每个串取一个字母来构成一个新字符串,新字符串的第i个字母只能从第i行的字符串中选出,这样就得到了一个新的长度为n的字符串,请问这个字符串是否有可能为回文字符串?
思路
暴力求对称的两个字符串有没有相同的字符
Accepted code
/*
* @Autor: CofDoria
* @Date: 2021-01-10 19:44:44
* @LastEditTime: 2021-01-10 20:00:15
*/
#include <bits/stdc++.h>
using namespace std;
#define db double
#define ll long long
#define inf 0x3f3f3f3f
#define s(a, n) memset(a, n, sizeof(a))
#define debug(a) cout << '#' << a << '#' << endl
#define rep(l, a, b) for (register ll l = a; l < b; ++l)
#define per(l, a, b) for (register ll l = a; l >= b; --l)
#define _ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define _forit(i, c) \
for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); ++i)
bool fi = true;
const unsigned long long MOD = 1e9 + 7;
inline ll gcd(ll a, ll b) {
return (b == 0 ? a : gcd(b, a % b)); }
string s[100];
int m[100][35];
int t;
int n;
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
cin >> t;
while (t--) {
cin >> n;
memset(m, 0, sizeof(m));
for (int i = 0; i < n; i++) {
cin >> s[i];
for (int sz = s[i].size(), j = 0; j < sz; ++j) {
m[i][s[i][j] - 'a']++;
}
}
for (int i = 0; i < n / 2; i++) {
bool ok = false;
for (int j = 0; j < 26; j++) {
if (m[i][j] && m[n - i - 1][j]) {
ok = true;
break;
}
}
if (!ok) {
cout << "No" << endl;
goto end;
}
}
cout << "Yes" << endl;
end:;
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
I.对称之美
题目
给出一个字符串,求最长非回文子字符串的长度
思路
特判字符串 s s s 是否全为同一字符,若是,输出0;否则判断是否为回文串,是则输出 ∣ s ∣ − 1 |s|-1 ∣s∣−1,否则输出 ∣ s ∣ |s| ∣s∣
Accepted code
/*
* @Autor: CofDoria
* @Date: 2021-01-10 19:20:31
* @LastEditTime: 2021-01-10 19:28:37
*/
#include <bits/stdc++.h>
using namespace std;
#define db double
#define ll long long
#define inf 0x3f3f3f3f
#define s(a, n) memset(a, n, sizeof(a))
#define debug(a) cout << '#' << a << '#' << endl
#define rep(l, a, b) for (register ll l = a; l < b; ++l)
#define per(l, a, b) for (register ll l = a; l >= b; --l)
#define _ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define _forit(i, c) \
for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); ++i)
bool fi = true;
const unsigned long long MOD = 1e9 + 7;
inline ll gcd(ll a, ll b) {
return (b == 0 ? a : gcd(b, a % b)); }
map<char, int> s;
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
string a, b;
cin >> a;
b = a;
for (int i = 0; i < a.size(); i++) {
s[a[i]]++;
}
reverse(a.begin(), a.end());
// cout << a << endl << b << endl;
if (s.size() == 1) {
cout << 0;
return 0;
}
if (a == b) {
cout << a.size() - 1;
return 0;
}
cout << a.size();
// fclose(stdin);
// fclose(stdout);
return 0;
}