【做题笔记】CF1528B Kavi on Pairing Duty
Problem
题目大意:
在数轴上有 \(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;
}