xtu-1269 Similar Subsequence(dp+树状数组)

来源:互联网 发布:黑苹果mac os 11.12 编辑:程序博客网 时间:2024/06/04 01:03

Similar Subsequence

Accepted : 17 Submit : 73Time Limit : 10000 MS Memory Limit : 135536 KB

Similar Subsequence

For 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:

  • s i =min{s i ,s i+1 ,,s n }  for all a i =0 ;
  • s i =max{s i ,s i+1 ,,s n }  for all a i =1 .

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) .

Input

The 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  .

  • The number of test cases does not exceed 10 .
  • 1n20 
  • 1m500 
  • 0a i 1 
  • 1b i m 
  • b 1 ,b 2 ,,b m   are distinct.

Output

For each case, output an integer which denotes the number of subsequences modulo(10 9 +7) .

Sample Input

2 30 01 2 33 51 0 14 1 3 2 5

Sample Output

32

Note

For 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|1using 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;}


原创粉丝点击