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
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5734034.html