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;
    }
  • 相关阅读:
    Encrypted Handshake Message
    RSAParameters Struct
    What if JWT is stolen?
    What's the difference between JWTs and Bearer Token?
    RSA Algorithm Example
    第18届Jolt大奖结果公布
    Ruby on rails开发从头来(windows)(三十六) 调试技巧
    Ruby on rails开发从头来(四十二) ActiveRecord基础(主键和ID)
    YouTube开放基础技术架构 让用户建自家YouTube
    Ruby on rails开发从头来(四十) ActiveRecord基础(Boolean属性)
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/6865965.html
Copyright © 2011-2022 走看看