zoukankan      html  css  js  c++  java
  • 2017-5-14 湘潭市赛 Similar Subsequence 分析+四维dp+一些简单优化

    Similar Subsequence
    Accepted : 10           Submit : 53
    Time Limit : 10000 MS           Memory Limit : 135536 KB
    
    Similar Subsequence
    
    For given sequence A=(a1,a2,…,an), a sequence S=(s1,s2,…,sn) has shape A if and only if:
    
        si=min{si,si+1,…,sn} for all ai=0;
        si=max{si,si+1,…,sn} for all ai=1.
    
    Given sequence B=(b1,b2,…,bm), Bobo would like to know the number of subsequences of length n which have shape A modulo (109+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 a1,a2,…,an.
    
    The thrid line contains m integers b1,b2,…,bm.
    
        The number of test cases does not exceed 10.
        1≤n≤20
        1≤m≤500
        0≤ai≤1
        1≤bi≤m
        b1,b2,…,bm are distinct.
    
    Output
    
    For each case, output an integer which denotes the number of subsequences modulo (109+7).
    Sample Input
    
    2 3
    0 0
    1 2 3
    3 5
    1 0 1
    4 1 3 2 5
    
    Sample Output
    
    3
    2
    
    Note
    
    For the first sample, all three subsequences of length 2 are of shape A.
    
    Source
    XTU OnlineJudge 
    
    /**
    题目:Similar Subsequence
    链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1269
    题意:给定A序列和B序列。A序列的数为0或1。
    
    从B中取出一个长度和A相同的子序列S满足
    si=min{si,si+1,…,sn} for all ai=0;
    si=max{si,si+1,…,sn} for all ai=1.
    
    问这样的S序列有多少种。结果mod 1e9+7;
    个人分析过程:
    显然要对A序列来处理。
    假设最后一个是0,表明选的数,必须满足min{si,si+1,...,sn}。
    那么如何确定B序列中的某个位置作为它。
    最后一个数B序列任何位置皆可,无论a=0,1都可以满足min,max关系,因为只有它一个数。
    倒数第二个数如何确认?
    假设确定的最后一个数为x。
    an-1 = 0; 那么这个数要比x小。
    an-1 = 1; 那么这个数要比x大。
    
    an-2 = 0; 那么这个数要比前面选过的数都小。
    an-2 = 1; 那么这个数要比前面选过的数都大。
    1:    sn-2>sn-1
               sn-1>x
                     sn = x;
               sn-1<x
    0:    sn-2<sn-1
    
    维护当前选好的序列中的最大和最小。
    dp[i][j][k][flag]表示还要选i个数,当前选好的序列的最大值位置为j,最小值位置为k,
    上一次选的位置为flag,flag=0表示为j位置,flag=1表示为k位置,的方法数。
    因为:每次选了一个数后,位置一定是j或者k中的一个。
    if(a[i]==0){ 通过flag来判断上次的选的位置,然后向前枚举遍历找一个满足<a[k]的位置pos; dp[i][j][k][flag] += dfs(i-1,j,pos,1);}
    if(a[i]==1){ 通过flag来判断上次的选的位置,然后向前枚举遍历找一个满足>a[j]的位置pos; dp[i][j][k][flag] += dfs(i-1,pos,k,0);}
    
    if(i==0) return 1;
    
    等一下:先试试对A序列从左到右考虑。
    
    a1 = 0; 那么选择的第一个数为x必须满足B序列的x的右边比x大的数的集合为s,|s|>=n-1;
    a1 = 1; 那么选择的第一个数为x必须满足B序列的x的右边比x小的数的集合为s,|s|>=n-1;
    
    a2 = 0;从前一个更新的集合s中,选择一个数,选择的x必须满足B序列的x的右边比x大的数的集合为s,|s|>=n-2;
    
    a3 = ?; 同理。
    
    暂时不知怎么处理。
    
    再回去试试从右往左考虑A序列。
    
    正确思路:
    在上面分析的基础上,由于时间超限了,对向前枚举遍历找一个满足<a[k]的位置pos;向前枚举遍历找一个满足>a[j]的位置pos;
    这种操作优化一下。预处理mis[i]表示j<i, b[j]<b[i]的所有的j。mas[i]表示j<i, b[j]>b[i]的所有的j。
    时间刚刚好卡过去了。。9000多ms。题目时限10s。
    
    */
    
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> P;
    const int maxn = 1e5+100;
    const int mod = 1e9+7;
    LL dp[22][502][502][2];
    vector<int> mis[505];///mis[i]表示j<i, b[j]<b[i]的所有的j。
    vector<int> mas[505];///mas[i]表示j<i, b[j]>b[i]的所有的j。
    int n, m;
    int a[22], b[502];
    void init()
    {
        for(int i = 1; i <= m; i++){
            mis[i].clear();
            mas[i].clear();
        }
        for(int i = 1; i <= m; i++){
            for(int j = 1; j < i; j++){
                if(b[j]<b[i]){
                    mis[i].push_back(j);
                }
                if(b[j]>b[i]){
                    mas[i].push_back(j);
                }
            }
        }
    
    
    }
    LL dfs(int i,int j,int k,int flag)
    {
        if(i==0) return 1;
        LL &res = dp[i][j][k][flag];
        if(res!=-1) return res;
        res = 0;
        if(flag==0){///j
            if(j-1<i) return res = 0;
            if(a[i]==0){
                /// j 的前面 比b[k]小的数。j<k;
                int len = mis[k].size();
                for(int d = 0; d < len; d++){
                    if(mis[k][d]>=j) break;
                    res = (res+dfs(i-1,j,mis[k][d],1))%mod;
                }
            }else
            {
                int len = mas[j].size();
                for(int d = 0; d < len; d++){
                    res = (res+dfs(i-1,mas[j][d],k,0))%mod;
                }
            }
        }else///k
        {
            if(k-1<i) return res = 0;
            if(a[i]==0){
                int len = mis[k].size();
                for(int d = 0; d < len; d++){
                    res = (res+dfs(i-1,j,mis[k][d],1))%mod;
                }
            }else
            {
                int len = mas[j].size();
                for(int d = 0; d < len; d++){
                    if(mas[j][d]>=k) break;
                    res = (res+dfs(i-1,mas[j][d],k,0))%mod;
                }
            }
        }
        return res;
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)==2)
        {
            for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
            for(int i = 1; i <= m; i++) scanf("%d",&b[i]);
            init();
            memset(dp, -1, sizeof dp);
            LL ans = 0;
            for(int i = m; i >= n; i--){
                ans += dfs(n-1,i,i,0);
                ans %= mod;
            }
            printf("%I64d
    ",ans%mod);
        }
        return 0;
    }
  • 相关阅读:
    restful架构风格设计准则(四)资源表示和资源访问
    洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)
    HDU 6138 Fleet of the Eternal Throne(后缀自动机)
    BZOJ1278: 向量vector(计算几何 随机化乱搞)
    BZOJ2564: 集合的面积(闵可夫斯基和 凸包)
    POJ 1113 Wall(思维 计算几何 数学)
    POJ 3304 Segments(直线与线段相交)
    洛谷P1742 最小圆覆盖(计算几何)
    洛谷P4555 [国家集训队]最长双回文串(manacher 线段树)
    洛谷P3193 [HNOI2008]GT考试(dp 矩阵乘法)
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/6865965.html
Copyright © 2011-2022 走看看