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。

  $n\leq 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\times 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\n",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/51Nod1317.html

时间: 2024-10-24 16:23:20

51Nod1317 相似字符串对 容斥原理 动态规划的相关文章

两个字符串的编辑距离-动态规划方法

两个字符串的编辑距离-动态规划方法[转载] 概念 字符串的编辑距离,又称为Levenshtein距离,由俄罗斯的数学家Vladimir Levenshtein在1965年提出.是指利用字符操作,把字符串A转换成字符串B所需要的最少操作数.其中,字符操作包括: 删除一个字符     a) Delete a character 插入一个字符     b) Insert a character 修改一个字符     c) Replace a character 例如对于字符串"if"和&qu

禁止字符串 字符串上的动态规划

// 禁止字符串 字符串上的动态规划 // 挑战程序设计第二版 page 368 // 考虑只由'A','G','C','T'四种字符组成的DNF字符串 // 给定一个长度为k的字符串S,计算长度恰好为n的且 // 不包含S的字符串的个数输入结果对10009取膜 // 1<=k<=100 // 1<=n<=10000 // // 这道题想动态规划,肯定是n*k的算法,即10的七次方以内 // 的复杂度 // // 但是,之后就卡住了... // // 仔细研习了书上的思路,发现状态

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=3,k=4那么(

计算字符串的距离——动态规划

#include<iostream> #include<string.h> using namespace std; int dp[100][100]; int min(int a, int b) { if(a<b) return a; else return b; } int main() { char str1[100]; char str2[100]; cin>>str1>>str2; int num1 = strlen(str1); int n

8.动态规划(1)——字符串的编辑距离

动态规划的算法题往往都是各大公司笔试题的常客.在不少算法类的微信公众号中,关于“动态规划”的文章屡见不鲜,都在试图用最浅显易懂的文字来描述讲解动态规划,甚至有的用漫画来解释,认真读每一篇公众号推送的文章实际上都能读得懂,都能对动态规划有一个大概了解. 什么是动态规划?通俗地理解来说,一个问题的解决办法一看就知道(穷举),但不能一个一个数啊,你得找到最优的解决办法,换句话说题目中就会出现类似“最多”.“最少”,“一共有多少种”等提法,这些题理论上都能使用动态规划的思想来求解.动态规划与分治方法类似

97. 交错字符串

题目描述: 给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的. 示例 1: 输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"输出: true示例 2: 输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"输出: false 思路: 设dp[i][j]表示

WildcardMatching和Regex,通配符匹配和正则表达式匹配

WildcardMatching:通配符匹配 算法分析: 1. 二个指针i, j分别指向字符串.匹配公式. 2. 如果匹配,直接2个指针一起前进. 3. 如果匹配公式是*,在字符串中依次匹配即可. 注意记录上一次开始比较的位置 Implement wildcard pattern matching with support for '?' and '*' '?' Matches any single character. '*' Matches any sequence of character

gdkoi前的复习

又浪了一天…… 整理下学的,这两天都温习(预习)一下吧. 27号就是gdkoi了好怕…… 数据结构 ------树 -------------平衡树 -------------线段树/树状数组 -------------树套树 -------------可持久化还有主席树 -------------树链剖分 -------------line-cut-tree -----字符串 -------------AC自动机 -------------后缀数组 -------------后缀自动机 算法

{CSDN}{英雄会}{反相互}

思路: 给定一个字符串,求两个不重叠的字串,他们翻转互补.其中一个字符串可以是删掉最多两个字符的原字符串子串. 动态规划,由于可以对子串进行删除操作,我首先想到了LCS问题,但需要枚举所有的长度,这样复杂度为O(N^3),不可取. 由于长度线性增加,考虑使用二分查找目的长度,这样复杂度为O(N^2*log(N)). 需要查找两次,查找子串(ln)的长度等于被查找子串(ln+k)的LCS长度,那么存在相应的子串互补,其中k为删掉的字符数,题中为2. 这样题中复杂度与k无关.但是,这个方法一直没有A