[CodeForces-759D]Bacterial Melee

题目大意:
  有一串n个字母,每个位置的字母可以同化边上的一个字母,
  比如:ab可以变成aa或者bb。
  相对的两个同化不能同时发生,比如ab不能变成ba。
  现在给你一个字符串,问你经过任意次数的同化过程,最多能生成多少个字符串。

思路:
  考虑同化过后的字符串与同化前的字符串的关系。
  如果我们把一个字符串中相邻且相同的字母缩在一起,那么我们可以发现每一次同化就相当于从原串中去掉了一个字符。
  这也就意味着同化过后的串一定是原串的一个子序列。
  同样,如果一个串是原串的一个子序列,它一定能由原串同化而来。
  我们可以先统计一下原串不同长度子序列的个数。
  对于一个长度为l的子序列,它里面有n-l个字符被缩过,那么缩之前的串总共有C(n,l)种可能。
  不同的子序列数量可以用DP求出来。
  f[i][j]表示以字符j结尾的长度为i的子序列数量,则f[i][j]=sum{f[i-1][k]|k≠j}+1,枚举i,j,k,时间复杂度O(n^2*26)。
  如果直接枚举k会TLE,只能过11个点,我们可以考虑用sum[i]记录长度为i的子串的数量和。
  由于结尾位置的字符已确定,所以组合数用C(n-1,l-1)算,时间复杂度O(n^2)。

 1 #include<cstdio>
 2 #include<cctype>
 3 typedef long long int64;
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x; 
10 }
11 const int N=5001,SIGMA=27,mod=1e9+7;
12 char s[N];
13 int f[N][SIGMA],sum[N],fact[N],factinv[N];
14 inline int idx(const char &ch) {
15     return ch-'a'+1;
16 }
17 void exgcd(const int &a,const int &b,int &x,int &y) {
18     if(!b) {
19         x=1;
20         y=0;
21         return;
22     }
23     exgcd(b,a%b,y,x);
24     y-=a/b*x;
25 }
26 inline int inv(const int &x) {
27     int ret,tmp;
28     exgcd(x,mod,ret,tmp);
29     return (ret%mod+mod)%mod;
30 }
31 inline int C(const int &n,const int &m) {
32     return (int64)fact[n]*factinv[n-m]%mod*factinv[m]%mod;
33 }
34 int main() {
35     const int n=getint();
36     scanf("%s",s);
37     fact[0]=factinv[0]=1;
38     for(register int i=1;i<n;i++) {
39         fact[i]=(int64)fact[i-1]*i%mod;
40         factinv[i]=inv(fact[i]);
41     }
42     sum[0]=1;
43     for(register int i=0;i<n;i++) {
44         const int ch=idx(s[i]);
45         for(register int i=1;i<=n;i++) {
46             sum[i]=(sum[i]-f[i][ch]+mod)%mod;
47             f[i][ch]=(sum[i-1]-f[i-1][ch]+mod)%mod;
48             sum[i]=(sum[i]+f[i][ch])%mod;
49         }
50     }
51     int ans=0;
52     for(register int i=1;i<=n;i++) {
53         ans=(ans+(int64)C(n-1,i-1)*sum[i]%mod)%mod;
54     }
55     printf("%d\n",ans);
56     return 0;
57 }

 

posted @ 2017-11-09 14:02  skylee03  阅读(234)  评论(0编辑  收藏  举报