题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3864
题意:
题解:
发一张图感受一下…:
令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示考虑到第
i
i
i位,当前
l
c
s
lcs
lcs的集合为
j
j
j的方案数
考虑维护一个
t
r
a
n
s
[
S
]
[
k
]
trans[S][k]
trans[S][k]表示在当前
S
S
S的集合后面多了一个字符
k
k
k(ACGT的一个)
注意到当
i
i
i固定时
l
c
s
[
i
]
[
j
]
、
l
c
s
[
i
]
[
j
−
1
]
lcs[i][j]、lcs[i][j-1]
lcs[i][j]、lcs[i][j−1]差
≤
1
\le 1
≤1,所以可以将差分数组状压一下,
t
r
a
n
s
trans
trans转移显然,枚举当前位转移:
t
m
p
[
0
]
[
i
]
=
S
tmp[0][i]=S
tmp[0][i]=S第
i
i
i位是否为1
t
m
p
[
1
]
[
i
]
=
m
a
x
(
t
m
p
[
0
]
[
i
]
,
t
m
p
[
1
]
[
i
−
1
]
)
tmp[1][i]=max(tmp[0][i],tmp[1][i-1])
tmp[1][i]=max(tmp[0][i],tmp[1][i−1])
t
m
p
[
1
]
[
i
]
=
m
a
x
(
t
m
p
[
1
]
[
i
]
,
t
m
p
[
0
]
[
i
−
1
]
+
1
)
−
−
−
(
i
这
一
位
恰
好
为
k
)
tmp[1][i]=max(tmp[1][i],tmp[0][i-1]+1) ---(i这一位恰好为k)
tmp[1][i]=max(tmp[1][i],tmp[0][i−1]+1)−−−(i这一位恰好为k)
t
r
a
n
s
[
S
]
[
k
]
=
∑
i
=
0
n
−
1
(
t
m
p
[
1
]
[
i
+
1
]
−
t
m
p
[
1
]
[
i
]
)
∗
(
2
i
)
trans[S][k]=\sum_{i=0}^{n-1}(tmp[1][i+1]-tmp[1][i])*(2^{i})
trans[S][k]=∑i=0n−1(tmp[1][i+1]−tmp[1][i])∗(2i) 将差分数组复原
d
p
[
i
]
[
t
r
a
n
s
[
S
]
[
k
]
]
=
∑
d
p
[
i
−
1
]
[
S
]
dp[i][trans[S][k]]=\sum dp[i-1][S]
dp[i][trans[S][k]]=∑dp[i−1][S]
对于dp的S,显然S中1的个数就是lcs的长度
统计一下即可。
注意这题卡空间,我WA了16次才过。。最后删了个头文件过了qaq
代码:
// by Balloons
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int inf = 1 << 29;
const int maxn=1001,mod=1e9+7;
int T;
const char ss[]="ACGT";
char s[17];
int m;
int dp[maxn][(1<<15)+5],trans[(1<<15)+5][5],a[17];
int n;
int ans[111];
int tmp[2][16]; // 差分数组
int solve(int S,int ch){
memset(tmp,0,sizeof tmp);
for(int i=1;i<=n;i++)tmp[0][i]=tmp[0][i-1]+(((S>>(i-1))&1));
for(int i=1;i<=n;i++){
int mx=0;
if(a[i]==ch)mx=max(mx,tmp[0][i-1]+1);
mx=max(max(mx,tmp[0][i]),tmp[1][i-1]);
tmp[1][i]=mx;
}
int res=0;
for(int i=0;i<n;i++)res+=(tmp[1][i+1]-tmp[1][i])*(1<<i);
return res;
}
int c1(int x){int cnt=0;while(x){if(x&1)++cnt;x>>=1;}return cnt;}
int main(){
scanf("%d",&T);
while(T--){
scanf("%s",s+1);scanf("%d",&m);
memset(dp,0,sizeof dp);memset(ans,0,sizeof ans);
n=strlen(s+1);int limit=(1<<n);
for(int i=1;i<=n;i++){
for(int j=0;j<4;j++){
if(s[i]==ss[j]){a[i]=j+1;break;}
}
}
for(int S=0;S<=limit-1;S++){
for(int i=1;i<=4;i++){
trans[S][i]=solve(S,i);
}
}
dp[0][0]=1;
for(int i=1;i<=m;i++){
for(int S=0;S<=limit-1;S++){
for(int k=1;k<=4;k++){
(dp[i][trans[S][k]]=dp[i][trans[S][k]]+dp[i-1][S])%=mod;
}
}
}
for(int S=0;S<=limit-1;S++){
(ans[c1(S)]+=dp[m][S])%=mod;
}
for(int i=0;i<=n;i++)printf("%d\n",ans[i]);
}
return 0;
}