题目链接:

https://jzoj.net/senior/#main/show/6084

https://www.luogu.org/problemnew/show/P4916

题目:

题解:

注:本题解大部分摘自Imagine大佬提供在洛谷的题解

我们设$f(x)$表示最小循环节长度为x的合法序列数,那么有$ans=\sum_{d|gcd(n,m)}\frac{1}{d}f(d)$

这是因为最小循环节为d的序列对应的环会被计算d次,比如

  • 0101,最小循环节长度为 2(循环节为 01),其对应的环会被统计 2 次(序列 0101 与 1010)
  • 0111,最小循环节长度为 4(循环节为 0111),其对应的环会被统计 4 次(序列 0111,1011,1101,1110)
  • 1111,最小循环节长度为 1(循环节为 1),其对应的环会被统计 1 次(序列 1111)

直接求$f(x)$并不好求,我们令$g(x)=\sum_{d|x}f(d)$,即$g(x)$表示最小循环节是x的因子的合法序列的个数。那么可以莫比乌斯反演来求$f(x)$,$f(x)=\sum_{d|x}\mu(d)g(\frac{x}{d})$

问题转化为了如何快速的求$g(x)$

注意到这样一个事实:对于长度为 $a$ 且恰好有 $b$ 颗黑色珠子的一段珠子,我们求 $g(a)$,等同于求下面方程的整数解的数量:

$$x_0 + x_1 + ... + x_{a - b} = b(0 \leq x_i \leq k, 0 \leq x_0 + x_{a - b} \leq k)$$

即被 $a - b$ 颗白色珠子划分开的 $a - b + 1$ 段黑色珠子的和为 $b$,且满足每连续一段长度不超过 $k$ 的限制条件。运用生成函数的知识,求上面方程的解的数量等同于求如下多项式 $h(x)$ 中 $x^b$ 的系数:

$$h(x) = \left(\sum_{i = 0}^{k} x^i\right) ^ {a - b - 1} \left( \left(\sum_{i = 0}^{k} x^i\right)^2{\rm mod}\ x^{k + 1}\right)$$

进一步地,有

$$h(x) = \left(\sum_{i = 0}^{k} x^i\right) ^ {a - b - 1} \left(\sum_{i = 0}^{k} (i +1)x^i\right)$$

我们转化一下。由于 $\sum_{i = 0}^k x^i = \frac{1 - x^{k + 1}}{1 - x}$,因此有:

$$h(x) = \left(\frac{1 - x^{k + 1}}{1 - x}\right) ^ {a - b - 1} \left(\sum_{i = 0}^{k} (i +1)x^i\right)$$

再展开右侧的式子 $\sum_{i = 0}^k(i + 1)x^i$:

$$\begin{aligned}\sum_{i = 0}^k (i +1)x^i &= x^0 + 2x^1 + 3x^2 + \cdots + (k + 1)x^k\\ &= (x^0 + x^1 + \cdots + x^k) + (x^1 +x^2 + \cdots + x^k)+ \cdots + x^k \\ &= \frac{x^0 - x^{k + 1}}{1 - x} + \frac{x^1 - x^{k + 1}}{1 - x} + \cdots + \frac{x^k - x^{k - 1}}{1 - x} \\ &= \frac{(x^0 + x^1 + \cdots + x^k) - (k + 1)x^{k + 1}}{1 - x} \\ &= \frac{\frac{x^0 - x^{k + 1}}{1 - x} - (k + 1)x^{k + 1}}{1 - x} \\ &= \frac{1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2}}{(1 - x)^2}\end{aligned}$$

因此,我们得到了:

$$\begin{aligned}h(x) &= \left(\frac{1 - x^{k + 1}}{1 - x}\right) ^ {a - b - 1} \frac{1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2}}{(1 - x)^2} \\ &= \frac{(1 - x^{k + 1})^{a - b - 1}}{(1 - x)^{a - b + 1}}(1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2})\end{aligned}$$

其中,$(1 - x^{k + 1})^{a - b - 1}$ 可化为 $\sum_{i = 0}^{\infty}\binom{a - b - 1}{i}(-1)^ix^{(k + 1)i}$,而 $\frac{1}{(1 - x)^{a - b + 1}}$ 即 $(1 - x)^{-(a - b + 1)}$,可通过负整数次幂的二项式定理化为 $\sum_{i = 0}^{\infty}\binom{a - b + i}{i}x^i$,因此有:

$$h(x) = \left(\sum_{i = 0}^{\infty}\binom{a - b - 1}{i}(-1)^ix^{(k + 1)i}\right)\left(\sum_{i = 0}^{\infty}\binom{a - b + i}{i}x^i\right)(1 - (k + 2)x^{k + 1} + (k + 1)x^{k + 2})$$

当把 $h(x)$ 化成该形式后,要求 $h(x)$ 中 $x^b$ 的系数就变得非常简单了。记 $s_1 = \sum_{(k + 1)i + j = b}(-1)^i\binom{a - b - 1}{i}\binom{a - b+ j}{j}$,$s_2 = (k + 2)\sum_{(k + 1)i + j = b - k - 1}(-1)^i\binom{a - b - 1}{i}\binom{a - b+ j}{j}$,$s_3 = (k + 1)\sum_{(k + 1)i + j = b - k - 2}(-1)^i\binom{a - b - 1}{i}\binom{a - b+ j}{j}$,$x^b$ 的系数为 $w$,那么有 $w = s_1 - s_2 + s_3$。

求 $s_1, s_2, s_3$ 只需按照 $s_1, s_2, s_3$ 的式子枚举 $i$ 即可,因为 $i$ 确定 $j$ 也就确定了。因此,我们可以在 $\frac{b}{k + 1}$ 的时间内求出 $h(x)$ 中 $x^b$ 的系数。

除去反演部分,我们就能够在 $\frac{\sigma(n)}{k + 1}$ 的时间内解决此题,其中,$\sigma(n)$ 表示 $n$ 的约数和。由于 $\sigma(n)$ 可近似看作 $n\ {\rm log}\ {\rm log}\ n$,接近线性,因此时间复杂度是非常优秀的。

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std; const int N=1e6+;
const int mo=;
int k,cnt;
int mu[N],prime[N],vis[N];
int f[N],g[N],fac[N],inv[N];
inline int read()
{
char ch=getchar();int s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
int qpow(int a,int b)
{
int re=;
for (;b;b>>=,a=1ll*a*a%mo) if (b&) re=1ll*re*a%mo;
return re;
}
void pre()
{
mu[]=;
for (int i=;i<N;i++)
{
if (!vis[i])
{
prime[++cnt]=i;
mu[i]=-;
}
for (int j=;j<=cnt&&prime[j]*i<N;j++)
{
vis[prime[j]*i]=;
if (i%prime[j]) mu[prime[j]*i]=-mu[i];
else break;
}
}
fac[]=;
for (int i=;i<N;i++) fac[i]=1ll*fac[i-]*i%mo;
inv[N-]=qpow(fac[N-],mo-);
for (int i=N-;i>=;i--) inv[i]=1ll*inv[i+]*(i+)%mo;
}
int gcd(int a,int b)
{
if (!b) return a;
return gcd(b,a%b);
}
int C(int a,int b)
{
return 1ll*fac[a]*inv[b]%mo*inv[a-b]%mo;
}
void add(int &a,int b)
{
if (b<) b+=mo;
a=(a+b)%mo;
}
int calc(int n,int m)
{
int res=;
for (int i=;i*(k+)<=m;++i)
{
int j=m-i*(k+);
if (i&) add(res,1ll*C(n-m-,i)*C(n-m+j,j)%mo*(mo-)%mo);
else add(res,1ll*C(n-m-,i)*C(n-m+j,j)%mo*%mo);
j=m-i*(k+)-k-;
if (j>=)
{
if (i&) add(res,1ll*(k+)*C(n-m-,i)%mo*C(n-m+j,j)%mo*%mo);
else add(res,1ll*(k+)*C(n-m-,i)%mo*C(n-m+j,j)%mo*(mo-)%mo);
}
j=m-i*(k+)-k-;
if (j>=)
{
if (i&) add(res,1ll*(k+)*C(n-m-,i)%mo*C(n-m+j,j)%mo*(mo-)%mo);
else add(res,1ll*(k+)*C(n-m-,i)%mo*C(n-m+j,j)%mo*%mo);
}
}
return res;
}
int n,m;
int main()
{
freopen("gift.in","r",stdin);
freopen("gift.out","w",stdout);
pre();
int T=read();
while (T--)
{
memset(f,,sizeof(f));
memset(g,,sizeof(g));
n=read();m=read();k=read();
int d=gcd(n,m);
for (int i=;i<=d;i++)
{
if (d%i) continue;
g[n/i]=calc(n/i,m/i);
}
for (int i=;i<=n;i++)
for (int j=i;j<=n;j+=i)
add(f[j],mu[i]*g[j/i]);
int ans=;
for (int i=;i<=n;i++)
{
if (n%i) continue;
add(ans,1ll*f[i]*qpow(i,mo-)%mo);
}
printf("%d\n",ans);
}
return ;
}

[jzoj 6084] [GDOI2019模拟2019.3.25] 礼物 [luogu 4916] 魔力环 解题报告(莫比乌斯反演+生成函数)的更多相关文章

  1. [jzoj 6101] [GDOI2019模拟2019.4.2] Path 解题报告 (期望)

    题目链接: https://jzoj.net/senior/#main/show/6101 题目: 题解: 设$f_i$表示从节点$i$到节点$n$的期望时间,$f_n=0$ 最优策略就是如果从$i, ...

  2. [jzoj 6093] [GDOI2019模拟2019.3.30] 星辰大海 解题报告 (半平面交)

    题目链接: https://jzoj.net/senior/#contest/show/2686/2 题目: 题解: 说实话这题调试差不多花了我十小时,不过总算借着这道题大概了解了计算几何的基础知识 ...

  3. [jzoj 6080] [GDOI2019模拟2019.3.23] IOer 解题报告 (数学构造)

    题目链接: https://jzoj.net/senior/#main/show/6080 题目: 题意: 给定$n,m,u,v$ 设$t_i=ui+v$ 求$\sum_{k_1+k_2+...+k_ ...

  4. [jzoj 6092] [GDOI2019模拟2019.3.30] 附耳而至 解题报告 (平面图转对偶图+最小割)

    题目链接: https://jzoj.net/senior/#main/show/6092 题目: 知识点--平面图转对偶图 在求最小割的时候,我们可以把平面图转为对偶图,用最短路来求最小割,这样会比 ...

  5. [jzoj 6086] [GDOI2019模拟2019.3.26] 动态半平面交 解题报告 (set+线段树)

    题目链接: https://jzoj.net/senior/#main/show/6086 题目: 题解: 一群数字的最小公倍数就是对它们质因数集合中的每个质因数的指数取$max$然后相乘 这样的子树 ...

  6. [jzoj 4528] [GDOI2019模拟2019.3.26] 要换换名字 (最大权闭合子图)

    题目链接: https://jzoj.net/senior/#contest/show/2683/0 题目: 题解: 不妨枚举一个点,让两颗树都以这个点为根,求联通块要么点数为$0$,要么包括根(即联 ...

  7. [jzoj 6087] [GDOI2019模拟2019.3.26] 获取名额 解题报告 (泰勒展开+RMQ+精度)

    题目链接: https://jzoj.net/senior/#main/show/6087 题目: 题解: 只需要统计$\prod_{i=l}^r (1-\frac{a_i}{x})$ =$exp(\ ...

  8. jzoj6101. 【GDOI2019模拟2019.4.2】Path

    题目链接:https://jzoj.net/senior/#main/show/6101 记\(f_i\)为从\(i\)号点走到\(n\)号点所花天数的期望 那么根据\(m\)条边等可能的出现一条和一 ...

  9. jzoj6099. 【GDOI2019模拟2019.4.1】Dist

    题目链接:https://jzoj.net/senior/#main/show/6099 考虑直接统计某个点到其它所有点的距离和 我们先把整个团当成一个点建图,处理出任意两个团之间的距离\(dis(i ...

随机推荐

  1. Android持久化保存cookie

    在解析网页信息的时候,需要登录后才能访问,所以使用httpclient模拟登录,然后把cookie保存下来,以供下一次访问使用,这时就需要持久化cookie中的内容. 在之前先科普一下基础知识: 什么 ...

  2. intellij idea 运行jedis

    到这里下载 http://mvnrepository.com/ jar包! 将jar包放入项目目录中,并引入! 引入包到项目中!创建对象! package com.company; import re ...

  3. 《ServerLess 给前端带来了什么》笔记

    1. Serverless 是什么 Serverless “无服务器架构”,即大量依赖第三方服务(也叫做后端即服务,即“BaaS”)或暂存容器中运行的自定义代码(函数即服务,即“FaaS”)的应用程序 ...

  4. sdwebimage缓存图片

    当使用SDWebImage时,如果用相同图片名的图片替换掉了原始缓存的图片,当再次请求的时候,还是使用的缓存图片,图片不会发生改变 原因:图片在NSCache中是以absolute url作为key存 ...

  5. struts2学习之基础笔记3

    第8章Struts 2类型转换 使用类型转换器 自定义类型转换器 步骤:1. Struts 2 构建流程 2.自定义类型转换器类(继承 DefaultTypeConverter /StrutsType ...

  6. firstChild与firstElementChild

    相同点: 都是获取父元素下的第一个节点对象 不同点: firstChild: IE6.7.8 第一个元素节点; 非IE6.7.8:返回第一个元素节点或文本节点 firstElementChild: I ...

  7. Java操作Kafka执行不成功

    使用kafka-clients操作kafka始终不成功,原因不清楚,下面贴出相关代码及配置,请懂得指点一下,谢谢! 环境及依赖 <dependency> <groupId>or ...

  8. CDR发展史-CorelDRAW经历了哪些版本?

    1989年CorelDRAW横空出世,它引入了全彩矢量插图和版面设计程序,这在计算机图形领域掀起了一场风暴般的技术革新.两年后,Corel又推出了首款一体化图形套件(第 3 版),将矢量插图.版面设计 ...

  9. 用Arcade表达式添加标签

    Arcade表达式是轻量级的脚本语言,我们可以通过全局变量$feature获取要素属性.比如说,要为城市添加标签,利用CITY_NAME列,我们可以编写语句:$feature.CITY_NAME.Ar ...

  10. 更新Maven的本地库

    1. 更新Maven的本地库 通常情况下,可改变默认的 .m2 目录下的默认本地存储库文件夹到其他更有意义的名称,例如, maven-repo 找到 {M2_HOME}\conf\setting.xm ...