【ybt金牌导航8-7-2】周期字符串 / 关于莫比乌斯反演的少量知识

周期字符串

题目链接:ybt金牌导航8-7-2

题目大意

求长度为 n 的只有小写字母组成的循环节长度为 n 的字符串个数。
循环节是最短的复制若干遍后拼起来跟原串相等的字符串。

思路

讲一讲莫比乌斯反演

莫比乌斯反演其实就是不断的用容斥,而莫比乌斯函数就是用来容斥的容斥系数。

φ(n)=d|nμ(d)nd 作为例子,我们来看看是怎么容斥的。

首先我们要知道 φ(n) 这个函数原本是干什么的,它叫欧拉函数,是 1n 中与 n 互质的数的个数。

那首先 d=1 的时候,意思就是把所有的数先都塞进答案中,答案加 n
那如果出现了一个 d 使得 gcd(n,d)>1,那 d 一定是 n 的某个质因数的倍数。
那你就会想,可以找到每个质因数 p,然后看能有多少个小于等于 n 的倍数,也就是 np 个,然后就给答案减去这个个数。
当然,你会发现它计算重复了。

如果两个不同的质因数 p1,p2,它们乘起来肯定是小于 n,也一定是 n 的因子。那如果有 p1p2|d,那这样的 d 会被前面的操作中被计算了 C21 次,那就多扣了一次,那答案就要加回去,那对于这两个质因子,这样的 dnp1p2 个,那就加回 np1p2
然后你会发现它还是会重复。

如果三个不同的质因数 p1,p2,p3,那乘起来还是 n 因子。那如果有 p1p2p3|d,那就被扣除了 C31C32 次,少扣了一次,那为了扣除一次,答案又要扣 np1p2p3

然后你会发现,它就是加回去,减回去,加回去,减回去不断进行。

那你会看到,当你处理的质因数个数是奇数的时候,它就是扣的操作;是偶数的时候,就是加的操作。
那当质因数个数为 k,这些质因数乘起来是 d,那答案就要加上 (1)knd
然后你再看莫比乌斯函数的定义,你会发现它就是 (1)k。别的时候不管,不需要加减,所以是 01 的时候等于 1 就是为了一开始的那个全部。

那就是这样的。

那就像上面的东西如果你有一个函数 g(m)=d|mf(d),你 g(m) 函数很好求,但是 f(d) 不好求,你就可以通过莫比乌斯反演求得 f(n)

关于这道题

我们首先设 fi 为循环节长度恰好为 i 的字符串个数,那题目要的就是 fn,这点没有问题。

那我们再弄一个 gi 为循环节长度恰好为 i 的因子的字符串个数,那可以看出 gi=d|ifd
那为什么要弄这个 gi 呢?我们会想到,如果一个子串可以通过多次复制得到你这个字符串,那字符串长度就一定是这个子串的长度的倍数。那反过来,子串的长度一定是这个字符串长度的因数。
那你会发现,任何长度为 i 的字符串的循环节长度都是 i 的因子的字符串个数。
gi=26i

那你会发现,你就可以反演了。
gi=d|ifdfi=d|igdμmd

代码

#include<cstdio> #define ll long long #define mo 1000000007 using namespace std; int n, yz[10001]; ll ans; ll ksm(ll x, ll y) {//快速幂求 26^x ll re = 1; while (y) { if (y & 1) re = (re * x) % mo; x = (x * x) % mo; y >>= 1; } return re; } void get_yz() {//求出这个数的所有因子 for (int i = 1; 1ll * i * i <= n; i++) if (n % i == 0) { yz[++yz[0]] = i; if (i * i != n) yz[++yz[0]] = n / i; } } ll get_miu(int x) {//求出一个数的 μ 值(定义法) if (x == 1) return 1; ll re = 1; for (int i = 2; 1ll * i * i <= x; i++) if (x % i == 0) { re *= -1; x /= i; if (x % i == 0) return 0; } if (x > 1) re *= -1; return re; } int main() { scanf("%d", &n); get_yz(); for (int i = 1; i <= yz[0]; i++) ans = (ans + (ksm(26, yz[i]) * get_miu(n / yz[i]) % mo + mo) % mo) % mo; printf("%lld", ans); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_8-7-2.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(108)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示