【做题笔记】CF1528B Kavi on Pairing Duty

Problem

CF1528B Kavi on Pairing Duty

题目大意:

在数轴上有 \(2n\) 个点,相邻两个点的距离为 \(1\)。现在要将这些点两两匹配成 \(n\) 个圆弧,要求任意两个圆弧要么等长,要么其中一个包含另一个,问方案数。

Solution

首先观察发现好像合法的匹配一定是若干层包含,里面一层并列,也就是这个样子:

中间三个句号表示剩下的点组成的圆弧都是等长的。

然后发现被样例 Hack 了:

观察发现被 Hack 的原因是可能有若干个等长的圆弧相交,剩下比他们小的圆弧在他们相交的部分中。

于是尝试修改结论:合法的匹配一定是外面若干层,每一层都是若干个等长的圆弧,最里面一层为若干个等长的圆弧。

接下来考虑统计答案,可以把外面的几层与最内层分开统计。

首先考虑外面几层。
对于每一层,发现唯一合法的匹配长这个样子:

所以假设外面几层总共有 \(k\) 层,则外面几层的方案数相当于将 \(k\) 个数分成若干个区间的方案。
这个东西相当于要在 \(k-1\) 个空隙中插入若干个隔板的方案数。发现每个空隙都有插或不插两种选项,所以方案数为 \(2^{k-1}\)

然后考虑最内层。
由于每个圆弧要等长,所以假设要匹配 \(l\) 个圆弧,则每个圆弧的长度必须是 \(l\) 的因数。而对于每一确定的长度,则有唯一对应的一种匹配的方案。所以内层的方案数为 \(\operatorname{d}(l)\)

所以整个题目的答案就是:

\[\sum\limits_{i=1}^n (\operatorname{d}(i) \times 2^{n-i-1}) \]

Code

//Think twice,code once.
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int mod=998244353;

int n,f[1000005],pw[1000005];
long long ans;

int main() {
	scanf("%d",&n);
	pw[0]=1;
	for (int i=1;i<=n;i++) pw[i]=2*pw[i-1]%mod;//pw[i] 表示 2^i
	for (int i=1;i<=n;i++)
		for (int j=i;j<=n;j+=i) f[j]++;//f[j] 表示 j 的因数个数。
	for (int i=1;i<=n;i++) ans=(ans+(long long)pw[max(n-i-1,0)]*f[i]%mod)%mod;//统计答案。
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-11-14 14:11  Mine_King  阅读(34)  评论(0编辑  收藏  举报