A Domino Disaster
题目大意
有n个1*2的多米诺骨牌,给定第一列的字母,求第二列对应的字母
主要思路
遍历所有字母,当前字母为U输出D,当前字母为D输出U,为L输出L,为R输出R
AC代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010;
int n, a[N], s[N];
signed main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n;
string s;
cin >> s;
for(int i = 0; i < s.size(); i++)
{
if(s[i] == 'L') cout << 'L';
else if(s[i] == 'R') cout << 'R';
else if(s[i] == 'U') cout << 'D';
else cout << 'U';
}
cout << endl;
}
return 0;
}
B MEXor Mixup
题目大意
给定一个序列的MEX的值a和序列的所有数xor的结果b,求这个序列的最短长度
主要思路
由于数组中未出现的最小整数为a, 所以当前序列一定有1~a-1这几个数,我们设这些数xor的结果为c
- 假设c^a == b,说明想要通过异或一个值得到b那么这个值一定为a,但是数列中不存在a,所以还需要异或两个数才能得到b
- 假设c^a != b,则我们让c(cb)这个数即可得到b
所以只需预处理一个异或的前缀和即可
AC代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 300010;
int n, a[N], s[N];
signed main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
for(int i = 1; i <= 300000; i++) s[i] = s[i - 1] ^ i;
int T;
cin >> T;
while(T--)
{
int a, b;
cin >> a >> b;
if(s[a - 1] == b) cout << a << endl;
else if((s[a - 1] ^ a) == b) cout << a + 2 << endl;
else cout << a + 1 << endl;
}
return 0;
}
C Carrying Conundrum
题目大意
给定一个错误的加法的定义,然后给定一个数n,求在错误的加法情况下有多少种数对和为n
主要思路
首先由于奇数位的进位只会影响奇数位,所以奇偶分开来看,把n根据奇偶拆成a和b,那么先考虑a有多少种组合方式,(0, a), (1, a - 1), …, (a - 1, 1), (a, 0),有a+1种,b也同理,所以有(a + 1) * (b + 1)种组合方式。
接下来考虑特殊情况,(0, a) (a, 0) (0, b) (b, 0)在组合过程中会有重复
可以组合成 0 0 a b, 0 b 0 a, a 0 0 b, a b 0 0
例如 0 0 a b和 a 0 0 b和a b 0 0重复所以答案-2
AC代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 300010;
int n, a[N], s[N];
signed main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
int n;
cin >> n;
int a = 0, b = 0;
string s = to_string(n);
for(int i = 0; i < s.size(); i++)
{
if(i % 2) a = a * 10 + s[i] - '0';
else b = b * 10 + s[i] - '0';
}
cout << (a + 1) * (b + 1) - 2 << endl;
}
return 0;
}
D Expression Evaluation Error
题目大意
给定一个数n和k,求在10进制下的k个数的和为n的同时,在11进制表示下k个数的和最大,求k个数
主要思路
核心思想:高位尽量不变,如果需要拆分则拆分低位
例如326 5这样的数我们先保证高位不变也就是100 100 100 26,然后继续处理低位,100 100 100 10 16
再举个例子100 2,考虑高位不动拆分低位,则10 90是优于99 1的,具体看代码注释
AC代码
#include <bits/stdc++.h>
using namespace std;
const int MAX = 200007;
const int MOD = 1000000007;
long long split(long long n) {//拆分n这个数
long long pow10 = 1;
while (pow10 <= n) {
if (pow10 == n) {return pow10 / 10;}
pow10 *= 10;
}
return pow10 / 10;
}
bool isPow10(long long n) {//判断是不是1000, 1, 100这样的数
long long pow10 = 1;
while (pow10 <= n) {
if (pow10 == n) {return true;}
pow10 *= 10;
}
return false;
}
void solve() {
long long s;
int n;
cin >> s >> n;
vector<long long> curr;//储存当前拆分的数
curr.push_back(s);
for (int mv = 0; mv < n - 1; mv++) {
long long x = -1;
for (int i = 0; i < curr.size(); i++) {
if (!isPow10(curr[i])) {//如果有不是100这样的数那么尽量拆分这样的数保证高位
x = curr[i];
curr.erase(curr.begin() + i);
break;
}
}
if (x == -1) {//如果都是100这样的数那么拆分一个最小的保证高位不动
long long mn = 1000000000007ll;
for (int i = 0; i < curr.size(); i++) {
if (curr[i] != 1) {
mn = min(mn, curr[i]);
}
}
for (int i = 0; i < curr.size(); i++) {
if (curr[i] == mn) {
x = curr[i];
curr.erase(curr.begin() + i);
break;
}
}
}
curr.push_back(split(x));
curr.push_back(x - split(x));
}
for (auto i : curr) {
cout << i << ' ';
}
cout << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tt; cin >> tt; for (int i = 1; i <= tt; i++) {solve();}
// solve();
}
群友D的骚做法,群友nb!
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 300010;
int n, m, a[N], s[N];
signed main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
int j;
cin >> n >> m;
for(int i = 1; i < m; i++)
{
j = pow(10, (int)log10(n - m + i));
n -= j;
cout << j << ' ';
}
cout << n << endl;
}
return 0;
}
E Non-Decreasing Dilemma
题目大意
给定一个序列有两个操作,给m次询问,每次询问给3个数t,x,y
- t == 1表示a[x] = y
- t == 2表示询问x~y区间的非递减子序列的数量
主要思路
有聚聚用树状数组+set过的也是一种思路
这里说一下线段树做法,对每一个节点开一个node包含以下
- sum表示该节点的答案
- l,r表示最左边和最右边的值
- L,R表示最左边和最右边的非递减子序列的最大长度
- s表示当前序列长度
代码根据节点信息维护即可
AC代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010;
struct node
{
int sum, l, r, L, R, s;
}tr[N * 4];
int n, m, a[N];
void pushup(node &root, node l, node r)
{
root.sum = l.sum + r.sum;
root.s = l.s+ r.s;
root.l = l.l, root.r = r.r;
root.L = l.L, root.R = r.R;
if(l.r <= r.l)
{
root.sum += l.R * r.L;
if(l.L == l.s) root.L += r.L;
if(r.R == r.s) root.R += l.R;
}
}
void build(int u, int l, int r)
{
if(l == r)
{
tr[u] = {1, a[l], a[r], 1, 1, 1};
return ;
}
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
node query(int u, int l, int r, int ql, int qr)
{
if(ql <= l && qr >= r) return tr[u];
else
{
int mid = l + r >> 1;
if(qr <= mid) return query(u << 1, l, mid, ql, qr);
else if(ql > mid) return query(u << 1 | 1, mid + 1, r, ql, qr);
else
{
node ansl = query(u << 1, l, mid, ql, qr);
node ansr = query(u << 1 | 1, mid + 1, r, ql, qr);
node ans;
pushup(ans, ansl, ansr);
return ans;
}
}
}
void modify(int u, int l, int r, int pos, int v)
{
if(l == r) tr[u] = {1, v, v, 1, 1, 1};
else
{
int mid = l + r >> 1;
if(pos <= mid) modify(u << 1, l, mid, pos, v);
else modify(u << 1 | 1, mid + 1, r, pos, v);
pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
}
signed main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
while(m--)
{
int t, x, y;
cin >> t >> x >> y;
if(t == 1) modify(1, 1, n, x, y);
else
{
cout << query(1, 1, n, x, y).sum << endl;
}
}
return 0;
}
F One-Four Overload
题目大意
给定一个n*m的二维字符数组使得X上的值等于周围’.'位置上的和且为5的倍数,求一种构造方法
主要思路
优先构造‘.’上的数,因为只能有1和4所以我们就使用这两个数
- 首先考虑不合法的情况,当X周围.的个数为奇数时一定不合法,因为无法凑出5的倍数
- 其次考虑性质,想要X位置上的数是5的倍数,要么周围是1和4,要么是两个1两个4,如果是两个1两个4的情况,一定要让1的对面是1,4的对面是4才不会影响后面的构造
- 基于性质所以我们先让奇数列的’.'为1,偶数列的为4,接下来考虑不合法情况,当 当前位置为X时,且当前位置的上一行的位置也为X,说明当前位置的右边一定与左边的数不同,也就是奇偶顺序改变
例如 X
1 X 4
- 然后再根据X周围的’.'判断X的值即可
AC代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 510;
int n, m;
char mp[N][N];
int ans[N][N];
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
signed main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
cin >> mp[i][j];
}
}
int p = 0;
for(int i = 1; i <= n; i++)
{
p = 0;
for(int j = 1; j <= m; j++)
{
if(mp[i][j] == 'X')
{
p ^= (mp[i - 1][j] == 'X');
int cnt = 0;
for(int k = 0; k < 4; k++)
{
if(mp[i + dx[k]][j + dy[k]] == '.') cnt++;
}
if(cnt & 1)
{
cout << "NO" << endl;
return 0;
}
}
else
{
ans[i][j] = ((j + p) & 1) ? 1 : 4;
}
}
}
cout << "YES" << endl;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(mp[i][j] == 'X')
{
int s = 0;
for(int k = 0; k < 4; k++)
{
if(mp[i + dx[k]][j + dy[k]] == '.') s += ans[i + dx[k]][j + dy[k]];
}
cout << s << ' ';
}
else cout << ans[i][j] << ' ';
}
cout << endl;
}
return 0;
}
本文介绍了三道编程竞赛题目及其解决方案,涉及 Domino Disaster、MEX 操作和错误加法问题。针对每道题目,分别给出了 AC 代码,并分析了主要思路。对于 Domino Disaster,题目要求根据第一列字母推导出第二列;在 MEX 操作中,通过预处理异或前缀和解决最短序列长度;错误加法问题中,根据奇偶性拆分数字以找到符合条件的数对组合。
2881

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



