首页 > 其他分享 >CF1715D 题解

CF1715D 题解

时间:2022-08-27 13:22:13浏览次数:88  
标签:putchar 48 int 题解 二进制位 CF1715D op

前言

题目传送门!

更好的阅读体验?

感觉挺不错的一道图论转化题。(其实也和图论关系不大。)

思路

对于每个条件 \(a_u \mid a_v = x\),二进制拆掉 \(x\)。如果 \(x\) 的二进制位 \(j\) 是 \(1\),说明 \(a_u\) 和 \(a_v\) 中,当前位也肯定有至少一个为 \(1\)。标记一下 \(f_{u, j} = f_{v, j} = 1\)。

由于字典序最小,所以我们尽量只让 \(a_{\max(u, v)}\) 的对应二进制位为 \(1\),这样可以使得 \(a_{\min(u, v)}\) 小一些。

由于要表示出点与点之间的关系,我们尝试建图。对每一个条件建图:连一条 \(u\) 与 \(v\) 间,边权为 \(x\) 的双向边。

然后,枚举每一位二进制位 \(j\),以及每一个点。对于每一个点,看与之相连的其他所有点(仍然是记为 \(u\), \(v\), \(x\))。

我们现在是看 \(a_u\) 的第 \(j\) 位(指的是二进制下。之后同理),要不要变成 \(1\)。

如果 \(x\) 的第 \(j\) 位是 \(0\),就跳过。否则,看 \(u\) 与 \(v\) 的大小关系。

  • 如果 \(u < v\),那么如果 \(f_v\) 的第 \(j\) 位没有被标记过,\(a_u\) 的第 \(j\) 位才必须为 \(1\)。否则应该让 \(a_v\) 为 \(1\),这样 \(u\) 就能小一些了。
  • 如果 \(u > v\),那么看当前 \(a_v\) 的结果。如果 \(a_v\) 的第 \(j\) 位为 \(0\),那 \(a_u\) 的第 \(j\) 位才必须为 \(1\)。

你可能会问,\(u = v\) 怎么办?显然 \(a_u \mid a_u = x\),直接表明了 \(a_u = x\)。因此在第一步时,就能特判掉 \(u = v\) 的情况,避免自环。

完整代码

#include <iostream>
#include <cstdio>
#define space putchar(' ')
#define endl putchar('\n')
using namespace std;
int read()
{
	char op = getchar(); int x = 0, f = 1;
	while (op < 48 || op > 57) {if (op == '-') f = -1; op = getchar();}
	while (48 <= op && op <= 57) x = (x << 1) + (x << 3) + (op ^ 48), op = getchar();
	return x * f;
}
void write(LL x)
{
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) write(x / 10);
	putchar(x % 10 + 48);
}
const int N = 1e5 + 5, M = 2e5 + 5;
struct Edge
{
	int now, nxt, w;
}e[M << 1]; //这里空间要开足!赛时调了好久。 
int head[N], cur;
void add(int u, int v, int w)
{
	e[++cur].now = v;
	e[cur].nxt = head[u];
	e[cur].w = w;
	head[u] = cur;
}
bool bit(int x, int j) {return x & (1 << (j - 1));} //x 的第 j 位 
bool flag[N][35]; //flag[i][j]表示a[i]的第j位是否有可能为1
int a[N];
bool calc(int u, int j)
{
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].now, x = e[i].w;
		if (!bit(x, j)) continue;
		if (u < v) {if (flag[v][j]) return true;}
		else {if (!bit(a[v], j)) return true;}
	}
	return false;
}
int main()
{
	int n = read(), m = read();
	for (int i = 1; i <= m; i++)
	{
		int u = read(), v = read(), x = read();
		for (int j = 1; j <= 30; j++)
			if (!bit(x, j))
				flag[u][j] = flag[v][j] = true;
		if (u == v) {a[u] = x; continue;} //特判,避免加边时造成自环 
		add(u, v, x), add(v, u, x);
	}
	for (int j = 1; j <= 30; j++)
		for (int i = 1; i <= n; i++)
			if (calc(i, j))
				a[i] |= (1 << (j-1));
	for (int i = 1; i <= n; i++) write(a[i]), space;
	return 0;
}

希望能帮助到大家!

首发:2022-08-25 14:57:13

标签:putchar,48,int,题解,二进制位,CF1715D,op
From: https://www.cnblogs.com/liangbowen/p/16630419.html

相关文章

  • 「NOI2016」网格 题解
    「NOI2016」网格题解前言感谢zqm学长提供调代码服务!本文中,所有没有特殊说明的连通都是指四连通,相邻都是指上下左右相邻。题目大意有一个$n\timesm$的网格,上......
  • 【IAP Kit】应用内支付订单参数相关问题解析
    ​1、创建的订单orderId长度是多少?答:orderId的长度最大是255。 2、InappPurchaseDetails中orderId和payOrderId有什么区别呢?答:orderId和payOrderId这两者的区别如下:o......
  • 优先队列-多路归并系列题解
    373.查找和最小的K对数字问题描述给定两个以升序排列的整数数组nums1和nums2 , 以及一个整数k 。定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来......
  • 【题解】CF1007D Ants
    传送门题意:有\(m\)对链,每对链要选择一条,使得选择的链两两不交,求一组方案。题解:一眼看上去就是一个2-sat,考虑一种暴力的做法,枚举每一条边,覆盖这条边的链两两连边。......
  • 题解 UVA10791
    前言:数学符号约定:\(p\):任意一个质数\(n\)或\(m\):任意一个正整数\(a_i\):唯一分解时质数的指数\(A\):集合若无特殊说明,本篇题解的数学符号将会严格按照上......
  • 20220823 模拟赛题解
    T1文件压缩DecriptionlinkSolution可以根据\(S'\)和\(p\)求出第一个字符,然后把\(S'\)sort一遍后得到字符串\(T\),那么我们就可以求出每一个字符的前驱和后继,所......
  • LeetCode 链表的中间结点算法题解 All In One
    LeetCode链表的中间结点算法题解AllInOnejs/ts实现重排链表链表的中间结点原理图解//快慢指针functionmiddleNode(head:ListNode|null):ListNode|n......
  • k8s问题解决
    问题1:问题描述:k8s中Terminating状态pod不能删除[root@master~]#kubectlgetpods-nmsNAMEREADYSTATUSRESTARTSAGEportal-78......
  • Unable to create an object of type 'DbContext'问题解决,网上搜来的没一个对的。
    用了很久的EFCore了,第一次遇到这个问题,觉得很奇怪,baidu了一下,都是要提供设计时工厂的答案。很明显这个做法是有问题的,都是DI的年代了,你的DbContext又不是动态生产了一堆......
  • P1399 [NOI2013] 快餐店 题解
    题目大意求一棵基环树的重心。即一个点,使得树上到其距离最长的点到其的距离最短。注意,这个点不一定是一个节点,可以在树上的任意位置。输出树上到其距离最长的点到其的距离......