B-3 SRM 08
描述
给长度为 n 的数列 A 和长度为 m 的数列 B,问有多少长度为 m 的数列 C 满足
输入格式
第一行俩整数 n 和 m
第二行 n 个整数 ,表示数列 A
第三行 m 个整数 ,表示数列 B
输出格式
一个整数,表示满足条件的数列 C 的个数模 后的值。
样例输入 1
5 3 1 5 2 4 7 7 9 6
样例输出 1
4
样例输入 2
4 2 7 7 7 7 3 4
样例输出 2
6
数据范围与约定
样例解释
第一个样例中,数列 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; }
当然 这时间复杂度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; }