首页 > 其他分享 >poker 题解

poker 题解

时间:2023-12-19 12:35:12浏览次数:27  
标签:poker return int 题解 线段 MAXN 端点 询问

原题链接:poker

赛时只有 \(40\) 分,改完之后感觉是一道好题,于是就来写篇题解。

题意

有 \(k\) 张扑克牌,\(n\) 种数字,每张牌都有两面,每一面分别写了一个数字,你可以选择打出这张牌的任意一面,但是不能两面同时打,也可以选择不打这张牌。有 \(q\) 个询问,每个询问给定 \(l\) 和 \(r\),判断能否打出 \(l\) 到 \(r\) 的顺子。

数据范围:\(n,k,q<=10^{6}\)。

思路

很容易想到暴力做法,每次 \(O(k)\) 扫一遍,贪心的去选择,时间复杂度 \(O(kq)\)。

考虑如何优化。这道题优化的方法是图论建模。对于每一张牌的两个面的数字 \(u\) 和 \(v\),连一条从 \(u\) 到 \(v\) 的边。这样就有了若干个连通块。这时我们会发现一些性质:对于一个大小为 \(N\) 的连通块来说,如果其中的边数 \(>=N\),那么一定可以一次性打出连通块中所有的牌;如果边数\(=N-1\),那么一定不能一次性打出连通块中所有的牌。边数为 \(N-1\) 其实就是一棵树。

我们先用并查集找出所有的树,记录一下 \(father\) 和 \(size\) 就行了。然后对于每一棵树,记 \(l\) 表示树中最小的数字,\(r\) 表示树中最大的数字。然后每一棵树都构造一条从 \(l\) 到 \(r\) 的约束线段,只要询问中的线段包含了任意一条约束线段,那么就是不合法的,因为一次性一定打不出约束线段中的每一个数字,证明见上。

于是现在问题转化成了给定若干条约束线段,询问 \(l\) 到 \(r\) 这条线段是否包含了任意一条约束线段。首先我们可以将约束线段按照右端点排序,将询问线段也按照右端点排序。动态维护一个变量 \(maxl\) 表示右端点小于当前询问线段的所有约束线段中,左端点的最大值。这样只要当前询问线段的左端点 \(<=maxl\) 的话,那么就包含了一条约束线段,是不合法的。反之则是合法的,时间复杂度 \(O(q+k)\),因为用了排序,总时间复杂度 \(O((q+k) \log (q+k))\),可以通过。当然最后一步也可以用树状数组,线段树或者扫描线来维护,但是比较麻烦。

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf 0x3f3f3f3f
#define inf_db 127
#define ls id << 1
#define rs id << 1 | 1
#define re register
typedef pair <int,int> pii;
const int MAXN = 1e6 + 10;
int n, k, u, v, fa[MAXN], Q, cnt, tmp = 1, deg[MAXN], to[MAXN], ans[MAXN];
pii sz[MAXN];
bool flag[MAXN];
int find(int x)
{
	if(x == fa[x]) return x;
	return fa[x] = find(fa[x]);
}
struct line
{
	int l, r, id;
}a[MAXN];
inline bool Cmp(line x, line y)
{
	if(x.r == y.r) return (x.l != y.l ? x.l > y.l : x.id < y.id);
	return x.r < y.r;
}
signed main()
{
	scanf("%lld%lld", &n, &k);
	for(int i = 1;i <= n;i++) fa[i] = i;
	for(int i = 1;i <= k;i++)
	{
		scanf("%lld%lld", &u, &v);
		fa[find(u)] = find(v);
		deg[u]++, deg[v]++;
	}
	for(int i = 1;i <= n;i++)
	{
		int id = find(i);
		sz[id].first++, sz[id].second += deg[i];
	}
	for(int i = 1; i <= n; i++)
		if (fa[i] == i && sz[i].first == sz[i].second / 2 + 1) to[i] = ++cnt;
	for (int i = 1; i <= n; i++) a[i].l = inf;
	for (int i = 1; i <= n; i++) {
		a[to[fa[i]]].l = min(a[to[fa[i]]].l, i);
		a[to[fa[i]]].r = max(a[to[fa[i]]].r, i);
	}
	cin >> Q;
	for(int i = 1;i <= Q;i++) scanf("%lld%lld", &a[cnt + i].l, &a[cnt + i].r), a[cnt + i].id = i;
	sort(a + 1, a + cnt + Q + 1, Cmp);int mxl = 0;
	for(int i = 1;i <= cnt + Q;i++) 
	{
		if (!a[i].id) mxl = max(mxl, a[i].l);
		else ans[a[i].id] = (a[i].l > mxl);
	}
	for (int i = 1; i <= Q; i++) cout << (ans[i] ? "Yes" : "No") << endl;
	return 0;
}

标签:poker,return,int,题解,线段,MAXN,端点,询问
From: https://www.cnblogs.com/Creeperl/p/17913449.html

相关文章

  • P3694 邦邦的大合唱站队 题解
    原题链接:P3694思路状态设计因为这道题\(m\)的范围非常小,所以可以用\(m\)来作为状态。设\(dp_{i}\)表示\(m\)支队伍的状态为\(i\)时最少让多少偶像出列。预处理在转移之前,我们先要预处理出序列的前缀和\(sum_{i,j}\)表示第\(i\)个数之前有多少个值为\(j\)......
  • [AGC054C] Roughly Sorted 题解
    题意定义一种操作为交换\(a_{i}\)和\(a_{i-1}\)。对于一个长度为\(n\)的排列,你需要操作若干次,使这个序列变合法,一个序列合法指:满足对于每一个\(1\lei\len\),都满足包含\(a_i\)的逆序对的个数不超过\(k\),并且要求最小化操作次数。现在给定一个操作后的序列,询问原序列可......
  • P2391 白雪皑皑 题解
    原题链接:P2391。并查集好题。首先我们知道,并查集在一个无向图中可以维护两点之间的连通性,判断条件为:\(find(u)==find(v)\)。而对于这道题来说,我们可以用并查集来维护一个序列区间的重叠性或者说区间的连通性。因为题目上说了后面的操作会覆盖前面的操作,所以我们可以考虑倒序进行......
  • [ABC239Ex] Dice Product 2 题解
    原题链接:ABC239Ex。题意不多赘述。看到求期望值,我们想到可以用期望DP。设\(dp_{i}\)表示最终结果大于等于\(i\)时的操作次数的期望值。那么我们可以得到一个基本的状态转移方程:\(dp_{i}=\frac{1}{n}\times\sum_{j=1}^{n}dp_{\left\lceil\frac{i}{j}\right\rceil}+......
  • Prefix Purchase 题解
    题意给定一个长度为\(n\)的序列\(ans\),初始值全部为\(0\)。你一共有\(k\)个硬币,你可以选择花\(a_{i}\)个硬币来使\(ans_{1}\)到\(ans_{i}\)中的所有数加一。求最终能得到的\(ans\)序列中字典序最大的一个。思路首先我们可以发现一个很显然的性质:如果满足\(a_{i}......
  • Sum of XOR Functions 题解
    题意给定一个数\(n\)和一个包含\(n\)个数的序列\(a\),求出以下式子模\(998244353\)的值:\(\sum_{i=1}^{n}\sum_{j=i}^{n}f(i,j)\times(j-i+1)\)。其中\(f(i,j)\)的值为\(a_{i}\oplusa_{i+1}\oplusa_{i+2}\oplus...\oplusa_{j}\)。思路首先我们可以考虑这道题的......
  • Candy Party (Hard Version) 题解
    原题链接:CF1868B2,简单版:CF1868B1。题意有\(n\)个人,第\(i\)个人手上最初有\(a_{i}\)颗糖。现在每个人可以把自己手中的糖选一些给不多于一个人,同时每个人也只能接受不多于一个人的糖,选出的糖的数量必须是二的次幂。问能否能让每个人最终手上的糖的数量相等。思路首先,这......
  • 【0909 B组】切蛋糕 题解
    原题链接:切蛋糕。题意给定一个\(n\)行\(m\)列的蛋糕,问横着切\(i\)刀,竖着切\(j\)刀后美味度最小的蛋糕的美味度尽可能大。一块蛋糕的美味度为它所含有的小块的美味度之和。数据范围:\(1\len,m\le14\)。思路看到数据范围,我们可以考虑一种类似于状态压缩的思想,先枚举......
  • Cyclic Operations 题解
    前言看这道题有好多巨佬都是用Tarjan来做的,在这里讲一个自认为比较简单的做法,(不到\(30\)行)。题意题意比较难讲,建议自己去看一下翻译,在这里不多赘述。思路首先看到题目中间给的一个每一次操作的式子:\(a_{l_{i}}=l_{(i\modk)+1}\)。仔细观察这个式子后会发现,其实每一次......
  • P4630 [APIO2018] 铁人两项 题解
    今天学习了圆方树,并且做了一道和这道题很像的题,于是就又来做了一下这道题。题意给定一张不保证连通的无向图。求有多少个点对\((a,b,c)\)满足\(a\)到\(c\)的简单路径上经过了点\(b\)。思路显然圆方树。点双缩点过后构造一颗圆方树,然后考虑如何计算答案。圆方树有一个实......