CF 731
A
(Link)[Problem - A - Codeforces]
题解
可以发现最小值求的是曼哈顿距离,任意条路径均可向上或向右提出,最终变成一个矩形的两条临边,这就是曼哈顿距离
再考虑特殊情况即三个点在同一行或同一列且障碍位于起点终点之间,距离要走一个弓形,也就是res += 2
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 55, M = 10010, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m;
int dp[N * 2][N][N], w[N][N], cnt;
int main (){
int t;
cin >> t;
while (t --) {
string s;
getline(cin, s);
int x1, y1, x2, y2, x3, y3;
cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
int res = abs(x1 - x2) + abs(y1 - y2);
if (x1 == x2 && x3 == x1 && (y1 - y3) * (y2 - y3) < 0) res += 2;
else if (y1 == y2 && y3 == y1 &&(x1 - x3) * (x2 - x3) < 0) res += 2;
cout << res << endl;
}
return 0;
}
B
(Link)[Problem - B - Codeforces]
题解
因为每一个字母不是放到左边就是右边,所以倒序找一下,看看当前这个是否在左边或右边,
如果都不在就不成立,如果在就移动一下标记
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 1e6 + 10, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m;
int a[N];
int main (){
int t;
cin >> t;
while (t --) {
string str;
cin >> str;
int l = 0, r = str.size() - 1;
bool ok = true;
for (int i = str.size() - 1; i >= 0; i -- ) {
if (str[l] == 'a' + i) {
l ++;
continue;
}
else if (str[r] == 'a' + i) {
r --;
continue;
}
else {
ok = false;
break;
}
}
if (ok) puts("Yes");
else puts("No");
}
return 0;
}
C
(Link)[Problem - C - Codeforces]
题解
因为要保持原序列相对顺序不能变,因此类似于归并排序,分别从左到右 看a b两个序列如果当前这个符合就加入到res中,否则看看另一个是否可以,如果都不行就false
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 55, M = 10010, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m, k;
int dp[N * 2][N][N], w[N][N], cnt;
int main (){
int t;
cin >> t;
while (t --) {
cin >> k >> n >> m;
vector<int> a(n), b(m), res;
for (int i = 0; i < n; i ++ ) cin >> a[i];
for (int i = 0; i < m; i ++ ) cin >> b[i];
int i = 0, j = 0;
while (i < n || j < m) {
bool ok = false;
while (i < n && a[i] <= k) { // 消除分类讨论的重复步骤
res.push_back(a[i]);
if (!a[i]) k ++;
i ++;
ok = true;
}
while (j < m && b[j] <= k) {
res.push_back(b[j]);
if (!b[j]) k ++;
j ++;
ok = true;
}
if (!ok) {
res.clear();
res.push_back(-1);
break;
}
}
for (int x : res) cout << x << ' ';
puts("");
}
return 0;
}
D
题解
例如 1 11 111 1111 11111
后面包含前面一定是连续的,可以进行连续操作叠加
aI+1 不完全包含ai,则ai+1 | ai == x (目标值) ai +1和x差的就是ai+1 ^ x
也就是最后ai+1要加上的就是ai + 1 ^ x
思路就是找到目标值找到差值,然后输出
& 找同 | 相加 ^找不同
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 55, M = 10010, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m;
int dp[N * 2][N][N], w[N][N], cnt;
int main (){
int t;
cin >> t;
while (t --) {
cin >> n;
int k = 0;
for (int i = 0; i < n; i ++ ) {
int x;
cin >> x;
k |= x;
cout << (x ^ k) << ' ';
}
puts("");
}
return 0;
}
E
(Link)[Problem - E - Codeforces]
题解
发现影响具有连续性(可传递)是一个递增的过程当前x处的温度仅由x-1或x+1处的最小温度转移过来的,所以初始化为正无穷,正着转移一遍反着转移一遍即可
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 3e5 + 10, M = 10010, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m, k;
int a[N], s[N];
int main (){
int t;
cin >> t;
while (t --) {
// string str;
// getline(cin, str);
cin >> n >> k;
for (int i = 1; i <= n; i ++ ) s[i] = 0x3f3f3f3f;
for (int i = 1; i <= k; i ++ ) cin >> a[i];
for (int i = 1; i <= k; i ++ ) {
int x;
cin >> x;
s[a[i]] = x;
}
for (int i = 2; i <= n; i ++ ) s[i] = min(s[i], s[i - 1] + 1);
for (int i = n - 1; i >= 1; i -- ) s[i] = min(s[i], s[i + 1] + 1);
for (int i = 1; i <= n; i ++ ) cout << s[i] << ' ' ;
puts("");
}
return 0;
}
F
(Link)[Problem - F - Codeforces]
题解
n次操作等价于a[1] = gcd(b[1], b[2],…, b [n + 1]) ,,所以操作一定小于n-1,成环的所以开二倍数组存一下即可
假设最多gcd了len个元素,那么len+1一定也成立,因此具有单调性可枚举操作数二分
对于不同长度的操作数还需要知道操作完后的数是什么,也就是gcd(a[l],a[l + 1].,a[r])是什么,等价于查询一个区间最值
区间最值可以用ST表
ST表:利用倍增的思想存储某个区间的最值
原数组为a[n]
st[i] [j] 表示从i开始到i + 2 ^ j - 1这个长度为2^j的区间的最值
可以发现st[i] [0] = a[i]
对于每一个 st[i] [j] 我们划分为两部分 从i到i + 2 ^ (j - 1) - 1 和从 i + 2 ^ (j - 1) 到i + 2 ^ j - 1
所以该区间的最值就是左右两边长度为2 ^ (j - 1) 中较大的一个
初始化为:
void ST_prework() { for(int i = 1; i <= n; i ++ ) st[i][0] = a[i]; for (int j = 2; j <= lg(n); j ++ ) for (int i = 1; i + (1 << j) - 1 <= n; i ++ ) st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); }对于查询某一个区间[l, r]来说,先找到不超过区间长度的最大的2^k,然后从查询st[l] [k]和
st[r - (1 << k) + 1] [k],因为求的是最大值所以覆盖住即可
int ST_query(int l, int r) { int k = lg(r - l + 1); return max(st[l][k], st[r - (1 << k) + 1][k]); }
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 2e5 + 10, M = 10010, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m, k;
int gcd(int a, int b) { // gcd具有连续性
return b ? gcd(b, a % b) : a;
}
int a[2 * N], st[N * 2][30];
int lg[N * 2];
void init() {
lg[1] = 0;
for (int i = 2; i < N * 2; i ++ )
lg[i] = lg[i / 2] + 1;
}
void ST_work() {
for (int j = 1; j <= lg[2 * n]; j ++ ) //枚举区间
for (int i = 1; i + (1 << j) - 1 <= 2 * n; i ++ ) // 从当前位置开始往后1 << j个元素要都在范围内
st[i][j] = gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); // 区间最大等价于子区间最大做比
}
int query(int l, int r) {
int len = lg[r - l + 1]; // 区间长度对应的小于等于的2^k的k
return gcd(st[l][len], st[r - (1 << len) + 1][len]);
// 只需要找到一个不超过len的最大2^k 将从[l, l + 2^k] 和[r - 2^k, r] 就可以将区间覆盖住
}
bool check(int x) {
bool ok = true;
int pre = query(1, 1 + x); // 区间连续gcd的值
for (int i = 2; i <= n; i ++ )
if (query(i,i + x) != pre) {
ok = false;
break;
}
return ok;
}
int main (){
int t;
cin >> t;
while (t --) {
cin >> n;
init();
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
a[i + n] = a[i];
st[i][0] = st[i + n][0] = a[i];
}
ST_work();
int l = 0, r = n;
while (l < r) { // 找大于等于的第一个数
int mid = l + r >> 1;
if (check(mid)) r= mid;
else l = mid + 1;
}
cout << l << endl;
}
return 0;
}
本文详细介绍了多种算法问题的解决方案,包括基于曼哈顿距离的路径优化、字符串排列验证、有序序列合并以及位运算求解序列问题。通过动态规划、区间最值查询和位运算技巧,展示了如何高效解决这些编程挑战。
614

被折叠的 条评论
为什么被折叠?



