zoukankan      html  css  js  c++  java
  • 【ybt金牌导航8-7-2】周期字符串 / 关于莫比乌斯反演的少量知识

    周期字符串

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

    题目大意

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

    思路

    讲一讲莫比乌斯反演

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

    (varphi(n)=sum_{d|n}mu(d)frac{n}{d}) 作为例子,我们来看看是怎么容斥的。

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

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

    如果两个不同的质因数 (p_1,p_2),它们乘起来肯定是小于 (n),也一定是 (n) 的因子。那如果有 (p_1p_2|d),那这样的 (d) 会被前面的操作中被计算了 (C_2^1) 次,那就多扣了一次,那答案就要加回去,那对于这两个质因子,这样的 (d)(dfrac{n}{p_1p_2}) 个,那就加回 (dfrac{n}{p_1p_2})
    然后你会发现它还是会重复。

    如果三个不同的质因数 (p_1,p_2,p_3),那乘起来还是 (n) 因子。那如果有 (p_1p_2p_3|d),那就被扣除了 (C_3^1-C_3^2) 次,少扣了一次,那为了扣除一次,答案又要扣 (dfrac{n}{p_1p_2p_3})

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

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

    那就是这样的。

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

    关于这道题

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

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

    那你会发现,你就可以反演了。
    (g_i=sumlimits_{d|i}f_dRightarrow f_i=sumlimits_{d|i}g_dmu_ frac{m}{d})

    代码

    #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;
    } 
    
    
  • 相关阅读:
    将vue文件script代码抽取到单独的js文件
    git pull 提示错误:Your local changes to the following files would be overwritten by merge
    vue和uniapp 配置项目基础路径
    XAMPP Access forbidden! Access to the requested directory is only available from the local network.
    postman与newman集成
    postman生成代码段
    Curl命令
    POST方法的Content-type类型
    Selenium Grid 并行的Web测试
    pytorch转ONNX以及TnesorRT的坑
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_8-7-2.html
Copyright © 2011-2022 走看看