zoukankan      html  css  js  c++  java
  • 汕头市队赛 SRM 08 B

    B-3 SRM 08

    描述

    给长度为 n 的数列 A 和长度为 m 的数列 B,问有多少长度为 m 的数列 C 满足

    1 leq C_1<C_2<...<C_mleq n

    (A_{c_1}+B_1) leq (A_{c_2}+B_2) leq ... leq (A_{c_m}+B_m)

    输入格式

    第一行俩整数 n 和 m

    第二行 n 个整数 A_i,表示数列 A

    第三行 m 个整数 B_i,表示数列 B

    输出格式

    一个整数,表示满足条件的数列 C 的个数模 10^9+7 后的值。

    样例输入 1

    5 3
    1 5 2 4 7
    7 9 6

    样例输出 1

    4

    样例输入 2

    4 2
    7 7 7 7
    3 4

    样例输出 2

    6

    数据范围与约定

    • 1 leq A_i, B_i leq 10^9
    • 1 leq m leq n
    • 1 leq n leq 2000, 1leq m leq 1000

    样例解释

    第一个样例中,数列 C 可以为 (1, 3, 5), (1, 4, 5), (2, 4, 5), (3, 4, 5)

    第二个样例中,数列 C 可以为 (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)

    这道题呢 很容易想到n^2m复杂度的dp f[i][j] 表示以j结尾长度为i(即匹配到第二个队列的第i个)的符合串

    水了点分

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int M=2005,mod=1e9+7;
    int read(){
        int ans=0,f=1,c=getchar();
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
        return ans*f;
    }
    int n,m,ans;
    int a[M],b[M],f[M][1005];
    int main()
    {
        n=read(); m=read();
        for(int i=1;i<=n;i++) a[i]=read(),f[i][1]=1;
        for(int i=1;i<=m;i++) b[i]=read();
        for(int i=2;i<=m;i++){
            for(int j=i;j<=n;j++){
                for(int k=1;k<j;k++) 
                    if(a[k]+b[i-1]<=a[j]+b[i]) f[j][i]=(f[j][i]+f[k][i-1])%mod;
            }
        }
        for(int i=m;i<=n;i++) ans=(ans+f[i][m])%mod;
        printf("%d
    ",ans);
        return 0;
    }
    View Code

     当然 这时间复杂度n一大绝对超时 这个时候就要想怎么降低时间复杂度了 

    观察后发现第三个循环枚举j前面所有点的时候 我们维护的信息明显可以用树状数组维护

    我们需要的点的信息要满足 i<j && k[p+1]+b[i-1]<=k[j]+b[i]

    那么 我们可以先给k【i】排一波序 然后进行一波离散化 方便后面树状数组的操作

    树状数组下标表示相对大小关系 

    然后我们可以类似递推地求出 如果只考虑大小关系 有多少个数满足上式

    考虑前后顺序 那么我们只要按原顺序逐渐插入树状数组中就可以保证了

    然后就是单点修改上传信息以及区间求和了

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int M=2007,mod=1e9+7;
    int read(){
        int ans=0,f=1,c=getchar();
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
        return ans*f;
    }
    int n,m,cnt,f[M],last[M],ans;
    int s[M],k[M],b[M],d[M],pos[M];
    struct node{int w,pos;}q[M];
    bool cmp(node a,node b){return a.w<b.w;}
    int lowbit(int x){return x&-x;}
    void add(int x,int v){
        while(x<=n){
            (s[x]+=v)%=mod;
            x+=lowbit(x);
        }
    }
    int query(int x){
        int ans=0;
        while(x) (ans+=s[x])%=mod,x-=lowbit(x);
        return ans;
    }
    int main()
    {
        n=read(); m=read();
        for(int i=1;i<=n;i++) k[i]=read(),f[i]=1,q[i]=(node){k[i],i};
        sort(q+1,q+1+n,cmp);
        d[++cnt]=q[1].w; pos[q[1].pos]=1;
        for(int i=2;i<=n;i++){
            if(q[i].w!=q[i-1].w) d[++cnt]=q[i].w;
            pos[q[i].pos]=cnt; 
        }
        for(int i=1;i<=m;i++) b[i]=read();
        for(int i=2;i<=m;i++){
            for(int j=1;j<=cnt;j++){
                int p=last[j-1];
                while(p<cnt&&d[p+1]+b[i-1]<=d[j]+b[i]) p++;
                last[j]=p;
            }
            for(int j=1;j<=cnt;j++) s[j]=0;
            add(pos[i-1],f[i-1]);
            for(int j=i;j<=n;j++){
                int sum=f[j];
                f[j]=query(last[pos[j]]);
                add(pos[j],sum);
            }
        }
        for(int i=m;i<=n;i++) (ans+=f[i])%=mod;
        printf("%d
    ",ans);
        return 0;
    } 
    View Code
  • 相关阅读:
    SpringDataJpa实体类常用注解
    I2C子系统
    input子系统
    platform深入
    运用层是怎样找到驱动的+open中子设备识别
    misc设备
    文章标题
    uboot2015第一阶段---SPL
    git工具使用
    Andriod底层第五课------HAL硬件抽象层
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7246866.html
Copyright © 2011-2022 走看看