Codeforces Round #742 (Div. 2) A~F

A. Domino Disaster

题意:由两种1 × 2的牌放置在2 × n的网格中铺满,一种是横向[L,R],一种是纵向[U,D],现给出其中一行,询问另外一行

分析:显然对于横向的牌的位置来说,上下是完全一样的,纵向相对。

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 1e9 + 7;

int n, m, t, k;

int s[N], dp[N], f[N];
char g[N];

string str;

vector<int> vec;

void solve()
{
	cin >> n >> str;
	for (int i = 0; i < n; i++)
	{
		if (str[i] == 'U') printf("D");
		else if (str[i] == 'D') printf("U");
		else printf("%c", str[i]);
	}
	puts("");
}

int main()
{
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

B. MEXor Mixup

题意:给出a,b 要求你使用最小数量的一组数,使得这组数的mex值为a,异或和为b,输出这组数的个数

名词解释:mex:数组中最小未出现过的非负整数

分析:对于mex,显然要求0到a-1所有数存在,对于异或和,分情况讨论即可,如果0到a-1的异或和正好为b,那么答案就是a,否则可以找到唯一的值使得异或和为b,如果这个值不为a,那么答案就是a+1,如果这个值为a,那么就加两个数,一个非a,一个非a异或上a的值,答案就是a+2

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 1e9 + 7;

int n, m, t, k;

int s[N], dp[N], f[N];
char g[N];

string str;

vector<int> vec;

void init()
{
	for (int i = 1; i < N; i++)
		s[i] = s[i-1] ^ i;
}

void solve()
{
	cin >> n >> m;
	if (s[n-1] == m) printf("%d\n", n);
	else if ((s[n-1] ^ m) == n) printf("%d\n", n+2);
	else printf("%d\n", n+1);
}

int main()
{
	init();
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

C. Carrying Conundrum

题意:算一个加法,进位是到下一位,Alice的加法比较特别,进位要到下两位,问Alice用他的方法算了a+b两个正数的和并告诉了你结果,你需要回答a+b有多少种可能的情况,

分析:将位置分奇偶看待,因为就位置来说,奇数位置和偶数位置相互无影响,而重新组合后的值a和b就是咱们日常的普通加法的结果了,因为有两个数的存在所以可以当做一个数可以存在0,另一个数不存在0,也是合法的,所以在允许0分别存在的情况下对于a有a+1种情况,b有b+1种情况,所有情况有(a+1)(b+1)种,不合法的情况有两种,一种是a取0,b取0,不合法,一种是a取a,b取b,对应的另一个数为0,不合法,所以答案为(a+1)*(b+1)-2

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 1e9 + 7;

int n, m, t, k;

int s[N], dp[N], f[N];
char g[N];

string str;

vector<int> vec;

void solve()
{
	cin >> n;
	vec.clear();
	while (n) vec.push_back(n % 10), n /= 10;
	reverse(vec.begin(), vec.end());
	int a = 0, b = 0;
	for (int i = 0; i < vec.size(); i++)
	{
		if (i & 1) a = a * 10 + vec[i];
		else b = b * 10 + vec[i];
	}
	printf("%d\n", (a+1) * (b+1) - 2);
}

int main()
{
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

D. Expression Evaluation Error

题意:给出一个十进制的数n,要求分成k份,k不大于max(n,100),要求把这些数当成十一进制计算,要求所得的和最大,问这k份如何分,输出这k份的答案

分析:显然在不进位的时候不会有损失,而如果必定损失的话,那么所在位置越小损失越小,所以可以暴力拆分,每次找到当前可拆分的最小位置进行拆分,拆分可以比之前多9个分解数,最多运行不超过11次,当满足题意后直接退出,当前可拆分数比k多的个数小于9个,所以可以先输出前k-1个,剩下的和就是最后一个值

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 1e9 + 7;

int n, m, t, k;

int dp[N], f[N];
char g[N];

string s;

void solve()
{
    cin >> s >> n;
    int m = s.size();
    vector<int> a(m);
    for (int j = 0; j < m; j++){
      a[j] = s[j] - '0';
    }
    int sum = 0;
    for (int j = 0; j < m; j++){
      sum += a[j];
    }
    while (sum < n)
	{
        for (int j = m - 2; j >= 0; j--)
		{
            if (a[j] > 0)
			{
		        a[j]--;
		        a[j + 1] += 10;
		        sum += 9;
		        break;
        	}
		}
    }
    vector<int> b;
    int p = 1;
    for (int j = m - 1; j >= 0; j--)
    {
        for (int k = 0; k < a[j]; k++)
	{
       	    b.push_back(p);
        }
        p *= 10;
    }
    while (b.size() > n)
    {
        int x = b.back();
        b.pop_back();
        b.back() += x;
    }
    for (int j = 0; j < n; j++)
    {
        cout << b[j];
        printf("%c", j == n - 1 ? '\n' : ' ');
    }
}

int main()
{
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

E. Non-Decreasing Dilemma

题意:给出n个数,m组操作,有2种操作,第一种单点修改,第二种区间查询,查询区间内连续不递减序列的个数

分析:考察线段树的应用,对于数组中两个分别连续不递减序列来说,相互之间值无影响的,所以只需要维护最左最右的最长连续不递减的序列长度,边界值,长度,答案即可,左边最长连续不递减的序列长度只有在原本就等于自己的序列长度且右界的值不大于右边左界的值的时候才会增加,变长,右边的最长连续不递减的序列长度同理。

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 1e9 + 7;

int n, m, t, k;

int s[N], dp[N], f[N];
char g[N];

string str;

vector<int> vec;

struct node{
	int l, r;//左右区间 
	int la, ra;//两边的值 
	int lb, rb; //左右最长连续范围 
	int sz;//长度 
	ll ans;
}tr[N << 2];

void pushup(node &u, node &a, node &b)
{
	u.l = a.l;
	u.r = b.r;
	u.la = a.la;
	u.ra = b.ra;
	u.sz = a.sz + b.sz;
	u.lb = (a.lb == a.sz && a.ra <= b.la) ? (a.lb + b.lb) : a.lb;
	u.rb = (b.rb == b.sz && a.ra <= b.la) ? (b.rb + a.rb) : b.rb;
	u.ans = a.ans + b.ans + ((a.ra <= b.la) ? 1ll * a.rb * b.lb : 0);
}

void pushup(int u)
{
	return pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void build(int u, int l, int r)
{
	if (l == r)
	{
		tr[u] = {l, r, s[l], s[l], 1, 1, 1, 1};
		return;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

void modify(int u, int l, int r, int a)
{
	if (tr[u].l >= l && tr[u].r <= r)
	{
		tr[u].la = tr[u].ra = a;
		return;
	}
	int mid = tr[u].l + tr[u].r >> 1;
	if (l <= mid) modify(u << 1, l, r, a);
	else modify(u << 1 | 1, l, r, a);
	pushup(u);
}

node query(int u, int l, int r)
{
	if (tr[u].l >= l && tr[u].r <= r) return tr[u];
	else
	{
		int mid = tr[u].l + tr[u].r >> 1;
		if (r <= mid) return query(u << 1, l, r);
		else if (l > mid) return query(u << 1 | 1, l, r);
		else
		{
			node left = query(u << 1, l, r);
			node right = query(u << 1 | 1, l, r);
			node res;
			pushup(res, left, right);
			return res;
		}
	}
}

void solve()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> s[i];
	build(1, 1, n);
	while (m--)
	{
		int a, l, r;
		cin >> a >> l >> r;
		if (a == 1) modify(1, l, l, r);
		else cout << query(1, l, r).ans << endl;
	}
}

int main()
{
    t = 1;
//    cin >> t;
    while(t--) 
        solve();
    return 0;
}

F. One-Four Overload

题意:给出n,m,nm的图,图中'X'的值必须是有相邻边的所有'.'位置的值的和且必须为5的倍数,而'.'的位置的值只能是1或4,若不存在输出"NO",存在输出YES,并在下n行输出nm的值的图

分析:学习的大佬的代码,因为'.'的值只能为1或4,所以显然'X'周围必须是偶数数量的'.',否则不成立,而如果是偶数数量的话,放进去的图只能是一块一块放入的,在最初所有数的值我们可以当做奇数行为1,偶数行为4,这样再放入单个'X'的时候,是无影响的,在放入块的时候,每一层,都会将整个内部进行反转(1变4,4变1),当'X'处于奇偶层之间时,会刚好凑成五的倍数,就是合法的,从外部进入的时候,奇数层就会反转,偶数层就反转回来了,在判定层数的时候,我们可以选定看该块的上层是否相连通,或者看该块的下面是否连通,判定之后就可以知道当前所在层数是奇还是偶。不能同时看,同时看的话判断不合理,就会出现本应该换层却没换的情况,本题还可以dfs搜,如果与'X'相邻的有4个,那么必定2个1,2个4,如果相邻的有两个那么必定是1和4,从上往下,从左往右搜,如果一个'X'的相邻位置有上和左,那么这两个位置就必定相对,从而在到'X'的时候,把另外地方的值固定,上下相等,左右相等也可,未尝试,不过排行榜过的人很多都是dfs。
代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 5e2 + 10, mod = 1e9 + 7;

int n, m, t, k;

int dx[4] = {-1, 0, 0, 1};
int dy[4] = {0, -1, 1, 0};

int s[N][N], dp[N][N], f[N][N];
char g[N][N];

string str;

vector<int> vec;

int judge(int a, int b)
{
	int res = 0;
	for (int i = 0; i < 4; i++)
		if (g[a+dx[i]][b+dy[i]] == '.')
			res++;
	return res;
}

void solve()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		scanf("%s", g[i] + 1);
	for (int i = 1; i <= n; i++)
	{
		k = 0;
		for (int j = 1; j <= m; j++)
		{
			if (g[i][j] == '.') 
				s[i][j] = ((i + k) & 1) ? 1 : 4;
			if (g[i][j] == 'X')
			{
				if (judge(i, j) & 1)
				{
					puts("NO");
					return;
				}
				if (g[i-1][j] == 'X') 
					k ^= 1;
			}
		}
	}
	puts("YES");
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (g[i][j] == '.')
				printf("%d%c", s[i][j], j == m ? '\n' : ' ');
			else
			{
				int ans = 0;
				for (int k = 0; k < 4; k++)
					if (g[i + dx[k]][j + dy[k]] == '.')
						ans += s[i + dx[k]][j + dy[k]];
				printf("%d%c", ans, j == m ? '\n' : ' ');
			}
		}
	}
}

int main()
{
    t = 1;
//    cin >> t;
    while(t--) 
        solve();
    return 0;
}
posted @   forleaves  阅读(58)  评论(4编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示