首页 > 其他分享 >ABC247F Cards 题解

ABC247F Cards 题解

时间:2022-12-02 20:12:30浏览次数:68  
标签:int 题解 卡牌 210000 ABC247F Cards define dp rightarrow

ABC247F Cards Solution

目录

更好的阅读体验戳此进入

题面

给定 $ n $ 张卡片,每张卡片正反面各有一个数,给定每张卡片正面和反面的数,保证正面的数构成的序列,和反面的数构成的,分别均为 $ 1 $ 到 $ n $ 的排列,可以选择任意张卡片并获得其正反面的数,要求最终所有获得的数至少包含 $ 1 $ 到 $ n $ 每个数至少一次。求有多少种取法,对 $ 998244353 $ 取模。

Solution

考虑卡片之间的联系,显然若一个数在同一张卡牌的正反面那么这张卡牌必须选择,否则无法凑齐一个排列,反之这个数一定会在两张卡牌中出现,且这两张卡牌一定至少有一张被选择,否则依然无法凑齐一个排列,这个很好理解。

于是我们考虑一些对于这种题的一般的套路,可以尝试建图,对于本题不难想到,我们将一张卡牌作为一个点,将这个点向卡牌上存在的数的另一次出现所在的卡牌连一条边。抽象地说,对于一个数所在的两张(或一张)卡牌位置 $ pos_{i, 0} $ 和 $ pos_{i, 1} $,其中一定有一个刚好为 $ i $,我们就是要从 $ i $ 向不等于 $ i $ 的那个 $ pos_i $ 连一条边,这里便不难想到从 $ i $ 向 $ pos_{i, 0} \oplus pos_{i, 1} \oplus i $ 连边即可。

不难想到这样会形成多个环,每一个环代表着其中几张卡牌,同时这些卡牌上的数在环内一定每个数都出现了两遍,如排列 $ { 1, 2, 3 } $ 和排列 $ { 2, 1, 3 } $,显然 $ i = 1 $ 时向数字 $ 1 $ 所在的另一张卡牌 $ 2 $ 和数字 $ 2 $ 所在的另一张卡牌 $ 2 $ 连边(不拿发现很有可能存在重边与自环,所以需要注意判重并忽略),对于 $ i = 2 $ 同理,最终一定会形成 $ 1 \rightarrow 2 \rightarrow 1 $ 和 $ 3 \rightarrow 3 $ 两个环,第一个环可以求出带有 $ 1, 2 $ 数字的卡牌的让 $ 1, 2 $ 都至少存在一次的卡牌选择方案数,第二个环则为 $ 3 $ 的方案数,将两者乘起来即为最终答案。并且环上每个边相连的两个点,或者说两张卡牌,至少要被选择一张,因为一条边连结的两个卡牌一定存在着相同的数,为了保证构成排列至少需要选择一个。

同时发现不同环的方案数,只跟环的长度有关,于是我们考虑令 $ dp(i) $ 表示 $ i $ 个数构成的环,则有边界 $ dp(1) = 1 $ 和 $ dp(2) = 3 $,和转移 $ dp(i) = dp(i - 1) + dp(i - 2) $,大概就是我们考虑向原环中插入第 $ i $ 个数,如果选择第 $ i $ 个数,那么任意的前 $ i - 1 $ 个数的合法方案都可以接上新的这个数,反之如果不选第 $ i $ 个,那么第 $ i $ 个的两侧都应该是选择的,这个时候我们直观地可以想到,固定其左右的两个然后由 $ dp(i - 3) $ 转移而来,但是这个是有遗漏的。观察发现对于 $ i $ 不选择的,是存在类似 $ \cdots \rightarrow 0 \rightarrow 1 \rightarrow i(0) \rightarrow 1 \rightarrow 0 \rightarrow \cdots $,也就是在固定三个之后左右各自接一个不选的,这个东西显然是不在 $ dp(i - 3) $ 里的,因为两个都不选接在一起形成环是不合法的,考虑如何正确地转移:我们可以考虑在 $ dp(i - 2) $ 的方案中找到任意一个选择的点,然后在其旁边接上 $ i $ 和另一个固定的选择的点,这样也是合法的且不重不漏,最终就是 $ dp(i) = dp(i - 1) + dp(i - 2) $。

于是考虑并查集维护好每个环的大小,$ \prod dp(siz_i) $ 即为最终的答案。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define MOD 998244353

template< typename T = int >
inline T read(void);

int N;
int P[210000], Q[210000];
int cnt[210000];
int pos[210000][2];
int f[210000];
bool vis[210000];
int ans(1);

class UnionFind{
private:
public:
    int fa[210000];
    int siz[210000];
    UnionFind(void){for(int i = 1; i <= 201000; ++i)fa[i] = i, siz[i] = 1;}
    int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
    void Union(int origin, int son){
        if(Find(origin) == Find(son))return;
        siz[Find(origin)] += siz[Find(son)], fa[Find(son)] = Find(origin);
    }
}uf;

int main(){
    N = read();
    f[1] = 1, f[2] = 3;
    for(int i = 3; i <= N; ++i)f[i] = (ll)(f[i - 1] + f[i - 2]) % MOD;
    for(int i = 1; i <= N; ++i)P[i] = read(), pos[P[i]][cnt[P[i]]++] = i;
    for(int i = 1; i <= N; ++i)Q[i] = read(), pos[Q[i]][cnt[Q[i]]++] = i;
    for(int i = 1; i <= N; ++i)
        uf.Union(i, pos[P[i]][0] ^ pos[P[i]][1] ^ i),
        uf.Union(i, pos[Q[i]][0] ^ pos[Q[i]][1] ^ i);
    for(int i = 1; i <= N; ++i)if(uf.Find(i) == i)ans = (ll)ans * f[uf.siz[uf.Find(i)]] % MOD;
    printf("%d\n", ans);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_10_25 初稿

标签:int,题解,卡牌,210000,ABC247F,Cards,define,dp,rightarrow
From: https://www.cnblogs.com/tsawke/p/16945511.html

相关文章

  • AtCoder Beginner Contest 247 题解
    AtCoderBeginnerContest247Solution目录AtCoderBeginnerContest247Solution更好的阅读体验戳此进入题面链接题面Luogu链接A-MoveRight题面SolutionCodeB-U......
  • vmware workstation SCSI磁盘格式虚拟机迁移到KVM之后无法启动的问题解决办法
    原文链接:https://blog.51cto.com/duron/2125821转换磁盘镜像格式之后导入KVM系统无法启动,但是可以进入恢复模式,可能是virtio的内核模块没有加载,把磁盘改为IDE模式后正常......
  • 题解【CF1592F2 Alice and Recoloring 2】
    CF1592F2AliceandRecoloring2解题报告。不一定更好的阅读体验。摘自我的构造题目选做例题IV。CF2800的构造就这?/cf/cf/cf(首先,操作2和操作3都是没有用......
  • 上海交通大学MBA常见问题解答
    欢迎您报考上海交通大学MBA!欢迎大家提问,我们会及时为您答疑解惑。报考上海交通大学MBA常见问题解答欢迎各位考生登陆​​www.sjtumba.org/bbs​​,在那您的问题将会得到我们......
  • P4910 题解
    前言题目传送门!更好的阅读体验?矩阵快速幂优化DP经典题。题目简述给定一个长度为\(n\)的环,每个位置可以填\(1\)或\(2\)。相邻两个不能同时填\(1\)。求方案数......
  • 新生第三次练习题解
    bs来送签到啦简单思考下就知道无论选择何种路线从左上角到右下角,通过平移后就等价于先向下走到底再向右走到底,所以只要两个循环累加下两条边的的价值就能得到答案(注意循......
  • sql题解--求出平台同时在线最多的人数
    题目-求出平台同时在线最多的人数题目需求根据用户登录明细表(user_login_detail),求出平台同时在线最多的人数。结果如下:cn7需要用到的表:用户登录明细表:us......
  • BZOJ 4833 最小公倍佩尔数 题解 (数论,推式子)
    题目链接神奇数论题。做这题需要知道两个结论:对于满足\(f_{i+2}=a\cdotf_{i+1}+b\cdotf_{i}\),也就是形式类似斐波那契数列的序列,有\(gcd(f_i,f_j)=f_{gcd(i,j)}\)(据......
  • 高通 QXDM5 安装后 打不开 问题解决
    QXDM5安装完成后,打开时显示找不到Qt5WebKit.dll文件,网上找了Qt5WebKit.dll等dll导入QXDM5目录,照样是失败,打不开程序,最终找到的解决方案如下:1.先卸载已安装的QXDM5和 Q......
  • shiro低版本更新到高版本(>1.10.0)出现报错问题解决
    近期漏洞爆出(ApacheShiro<1.10.0身份认证绕过漏洞),开始升级新版的jar包。升级过程1.修改pom文件shiro版本<!--shiro--><dependency><groupId>org.apache.......