HDU 5791 Two
dp[i][j]表示以a[i],b[j]为结尾的方案数,就是 k<i&&s<j 的dp[s][k]累加和。用个树状数组求和即可。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-8; void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } inline int read() { char c = getchar(); while(!isdigit(c)) c = getchar(); int x = 0; while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } return x; } const int maxn=1010; LL dp[maxn][maxn],c[maxn][maxn]; int n,m,a[maxn],b[maxn]; LL mod=1000000007; int lowbit(int x) { return x&(-x); } LL sum(int a,int b) { LL res=0; for(int x = a; x > 0; x -= lowbit(x)) { for(int y = b; y > 0; y -= lowbit(y)) { res += c[x][y]; } } return res; } void update(int i, int j, LL delta) { for(int x = i; x<=n; x += lowbit(x)){ for(int y = j; y <=m; y += lowbit(y)) { c[x][y] = (c[x][y]+delta)%mod; } } } int main() { 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]); LL ans=0; memset(c,0,sizeof c); memset(dp,0,sizeof dp); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(a[i]==b[j]) { dp[i][j]=sum(i-1,j-1)+1; update(i,j,dp[i][j]); ans=(ans+dp[i][j])%mod; } } } printf("%lld\n",ans); } return 0; }