http://acm.hdu.edu.cn/showproblem.php?pid=6806
给一个字符串 $S$ ,求与其相似的本质不同的字符串 $T$ 的个数:
相似的定义:
1.单词的可重集合相同。
2.对于一个词 $α$ ,它在 $S$ 中的第 $i$ 次出现和在 $T$ 中的第 $i$ 次出现的指数相差不超过1。
我会做的题当中唯一一道值得写题解的。
首先用map处理一下单词,给单词标号,就可以把字符串换成数列了。
之后可以发现,构造一个相似字符串的方法就是选择两个相邻的单词然后交换位置即可。
并且我们能够发现如果相邻两个单词一样那么交换与不交换没有差别。
那么设 $f[i]$ 为前 $i$ 个单词所组成的字符串的本质不同的字符串的个数,那么有:
如果 $a[i]==a[i-1]$ ,那么 $f[i]=f[i-1]$ 。显然 $a[i]$ 和 $a[i-1]$ 是不能交换了。
如果 $a[i]!=a[i-1]$ ,那么 $f[i]=f[i-1]+f[i-2]$ 。 $a[i]$ 和 $a[i-1]$ 交换与否两种情况累加即可。
复杂度 $O(Tnlog)$,log懒得优化了能过就行。
#include<bits/stdc++.h> #define fi first #define se second using namespace std; typedef long long ll; typedef pair<int,int>pii; const int N=1e5+5; const int p=1e9+7; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } map<string,int>mp; string s; int a[N],f[N]; int main(){ int T=read(); while(T--){ int n=read(),cnt=0; mp.clear(); f[0]=f[1]=1; for(int i=1;i<=n;i++){ cin>>s; if(!mp[s])mp[s]=++cnt; a[i]=mp[s]; if(i!=1){ if(a[i]==a[i-1])f[i]=f[i-1]; else f[i]=(f[i-1]+f[i-2])%p; } } printf("%d ",f[n]); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++