设 表示 序列前 项, 序列前 项, 与 共同作为 公共子序列 末尾的方案数,
首先有一个很显然的状态转移方程,
,时间复杂度 ,
对于这种 时才生效的状态, 可以在 时, 直接继承, 所以不妨直接省掉一维,
先 从小到大 枚举 , 设 表示以 这个 值 结尾, 与 前 项构成 公共子序列 的方案数量,
有 , 意为 以 这个 值 为末尾 转移到 以 这个 值 为末尾,
- 可以发现 在枚举 时是不变的, 因此可以方便的维护限制条件,
- 随着 从小到大 枚举, 在枚举时不断使用当前 完善决策集合即可实现后面 转移 .
时间复杂度 .
#include<bits/stdc++.h>
#define reg register
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 3005;
const int mod = 1e9 + 7;
int N;
int M;
int K;
int Len;
int Ans;
int num0;
int S[maxn];
int T[maxn];
int B[maxn<<1];
int F[maxn<<1];
bool is[maxn<<1][maxn<<1];
int main(){
N = read(), M = read(), K = read();
for(reg int i = 1; i <= N; i ++) B[++ Len] = S[i] = read();
for(reg int i = 1; i <= M; i ++) B[++ Len] = T[i] = read();
std::sort(B+1, B+Len+1);
Len = std::unique(B+1, B+Len+1) - B-1;
for(reg int i = 1; i <= N; i ++) S[i] = std::lower_bound(B+1, B+Len+1, S[i])-B;
for(reg int i = 1; i <= M; i ++) T[i] = std::lower_bound(B+1, B+Len+1, T[i])-B;
for(reg int i = 1; i <= K; i ++){
int s = read(), t = read();
int p = std::lower_bound(B+1, B+Len+1, s)-B;
if(p == Len+1 || B[p] != s) continue ; s = p;
p = std::lower_bound(B+1, B+Len+1, t)-B;
if(p == Len+1 || B[p] != t) continue ; t = p;
if(is[s][t]) continue ; is[s][t] = 1;
}
for(reg int i = 1; i <= N; i ++)
for(reg int j = 1, s = 1; j <= M; j ++){
int ts = s;
if(is[T[j]][S[i]]) s = (s + F[j]) % mod; // 可以转移到后面.
if(S[i] != T[j]) continue ;
Ans = (Ans + ts) % mod; F[j] = (F[j] + ts) % mod;
}
printf("%d
", Ans);
return 0;
}