• 51Nod1317 相似字符串对 容斥原理 动态规划


    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1317.html

    题目传送门 - 51Nod1317

    题意

      称一对字符串(A,B)是相似的,当且仅当满足以下条件:

      (1)字符串A和B都恰好包含N个字符;

      (2)A和B串中的每个字符都是小写字母的前k个字符,即A、B中只可能出现'a','b','c',...,('a'+k-1)这k个字符;

      (3)存在一个字符串C,满足:A+C=C+B。这里的“+”号表示字符串间的链接,即str1+str2 = str1str2,如:“aaa”+“csd”=“aaacsd”。

      现在给出N与k,问有多少种不同的相似字符串对,输出这个结果 mod 1,000,000,007的值。

      说明:两个字符串对(A,B)与(C,D)是不同的,只要 A!=C 或 B!=D。

      $nleq 10^9$

    题解

      显然满足 $A+C=C+B$ 的 $A$ 和 $B$ 循环同构。

      于是原问题变成了有多少对串循环同构。

      我们设 $dp_i$ 表示长度为 $i$ 的 不存在长度小于 $i$ 的循环节的 字符串个数。

      这里的循环节是指满足把该循环节串重复多次可以组成原串的子串。

      显然 $dp_i=k^i -sum_limits{j|i} dp_j$ 。

      答案为 $sum_limits{i|n} i imes dp_i$ ,因为任意一个循环节长度为 $i$ 的串都可以选择 $i$ 个串与它循环同构。

      由于 $n$ 的因数特别少,因数最多的情况下, $n=735134400$ ,因数个数为 1344 。(我搜了1分钟才搜出来……)

      所以我们可以把 $n$ 的因数搞出来,设因数个数为  $m$ ,然后 $O(m^2)$ DP 解决本问题。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int read(){
    	int x=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    	return x;
    }
    const int N=3005,mod=1e9+7;
    int n,k,v[N],m,dp[N];
    int Pow(int x,int y){
    	int ans=1;
    	for (;y;y>>=1,x=1LL*x*x%mod)
    		if (y&1)
    			ans=1LL*ans*x%mod;
    	return ans;
    }
    int main(){
    	n=read(),k=read(),m=0;
    	for (int i=1;i*i<=n;i++)
    		if (n%i==0){
    			v[++m]=i;
    			if (i*i!=n)
    				v[++m]=n/i;
    		}
    	sort(v+1,v+m+1);
    	int ans=0;
    	for (int i=1;i<=m;i++){
    		dp[i]=Pow(k,v[i]);
    		for (int j=1;j<i;j++)
    			if (v[i]%v[j]==0)
    				dp[i]=(dp[i]-dp[j]+mod)%mod;
    		ans=(1LL*dp[i]*v[i]+ans)%mod;
    	}
    	ans=(ans+mod)%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    安装开发工具
    CSS基础
    CSS动画
    CSS效果
    CSS布局
    CSS预处理语言
    React开发笔记
    Vue2.0学习笔记
    Vue-cli3.0开发笔记
    项目开发技巧
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/51Nod1317.html
Copyright © 2020-2023  润新知