Similar Subsequence | ||
Accepted : 17 | Submit : 73 | |
Time Limit : 10000 MS | Memory Limit : 135536 KB |
Similar SubsequenceFor given sequence A=(a 1 ,a 2 ,…,a n ) , a sequence S=(s 1 ,s 2 ,…,s n ) has shape A if and only if:
Given sequence B=(b 1 ,b 2 ,…,b m ) , Bobo would like to know the number of subsequences of length n which have shape A modulo (10 9 +7) . InputThe input contains zero or more test cases and is terminated by end-of-file. For each test case: The first line contains two integers n and m . The second line contains n integers a 1 ,a 2 ,…,a n . The thrid line contains m integers b 1 ,b 2 ,…,b m .
OutputFor each case, output an integer which denotes the number of subsequences modulo (10 9 +7) . Sample Input2 3 0 0 1 2 3 3 5 1 0 1 4 1 3 2 5 Sample Output3 2 NoteFor the first sample, all three subsequences of length 2 are of shape A . |
dp[i][j][x][y]表示a串中第i个元素,b串中的第j个元素,最小值为x,最大值为y时的方案数
dp[i][j][x][y]=∑dp[i-1][j'][x'][y'],[x',y']∈[x,y]
由于x,y中一定有一项等于b[j]因此可以省略一维,状态数为n*m^2
dp[i][j][k]中,
a[i]==0时,k为第i~n个被匹配的元素中最大值
a[i]==1时,k为第i~n个被匹配的元素中最小值
状态转移时用树状数组来维护:t[i][k]中i和k分别对应于dp[i][j][k]中的i和k
如果a[i]==0,sum[x]表示上下界为[1~x,k]的方案数之和
如果a[i]==1,sum[x]表示上下界为[k,1~x]的方案数之和
#include<bits/stdc++.h>
#define fuck(x) cout<<'['<<x<<']';
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int mod = 1e9 + 7;
const int MX = 500 + 5;
int a[25], b[MX], dp[25][MX][MX];
int n, m;
void add(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
if(x < 0) x += mod;
}
struct Tree {
int sum[MX];
int lowbit(int x) {
return x & (-x);
}
void update(int x, int v) {
while(x) {
add(sum[x], v);
x -= lowbit(x);
}
}
int query(int x) {
if(x == 0) return 0;
int ret = 0;
while(x <= m) {
add(ret, sum[x]);
x += lowbit(x);
}
return ret;
}
void clear() {
memset(sum, 0, sizeof(sum));
}
} t[25][MX];
int main() {
//reopen("in.txt", "r", stdin);
while(~scanf("%d%d", &n, &m)) {
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= m; i++) scanf("%d", &b[i]);
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
t[i][j].clear();
/*
初始化是个难点,如果a[1]==1,那么要设下界为最小值1
如果a[1]==0,那么要设下界为最大值m
if(a[1]==1) t[1][1].update(m,1);
else t[1][m].update(m,1);
*/
for(int i=1;i<=m;i++) dp[1][i][a[1]==1?1:m]=1;
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= m; j++) {
for(int k = 1; k <= m; k++) {
dp[i][j][k] = t[i][k].query(b[j]);
}
for(int k = 1; k <= m; k++) {
if(dp[i - 1][j][k] == 0) continue;
//匹配到第i-1个数位置,上下边界为[L,R]
int L = b[j], R = k;
if(a[i - 1] == 1) swap(L, R);
if(L > R) continue;
if(a[i] == 0) { //如果a[i]==0,则下边界就是b[j],因此要枚举上边界R
t[i][R].update(R, dp[i - 1][j][k]);
t[i][R].update(L - 1, -dp[i - 1][j][k]);
}
else { //如果a[i]==1,则下边界就是b[j],因此要枚举下边界L
t[i][L].update(R, dp[i - 1][j][k]);
t[i][L].update(L - 1, -dp[i - 1][j][k]);
}
}
}
}
int ans = 0;
for(int j = 1; j <= m; j++)
for(int k = 1; k <= m; k++)
add(ans , dp[n][j][k]);
printf("%d\n", ans);
}
return 0;
}