hdu 5791 dp

 


链接:戳这里


Two

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Problem Description
Alice gets two sequences A and B. A easy problem comes. How many pair of sequence A' and sequence B' are same. For example, {1,2} and {1,2} are same. {1,2,4} and {1,4,2} are not same. A' is a subsequence of A. B' is a subsequence of B. The subsequnce can be not continuous. For example, {1,1,2} has 7 subsequences {1},{1},{2},{1,1},{1,2},{1,2},{1,1,2}. The answer can be very large. Output the answer mod 1000000007.
 
Input
The input contains multiple test cases.

For each test case, the first line cantains two integers N,M(1≤N,M≤1000). The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.
 
Output
For each test case, output the answer mod 1000000007.
 
Sample Input
3 2
1 2 3
2 1
3 2
1 2 3
1 2
 
Sample Output
2
3
 


题意:

分别给出长度为n,m的序列,问有多少子序列a和b相等,ab元素的相对原数组位置一样


思路:

都知道是dp,说清楚点吧

dp[i][j] 表示当前a序列到位置i,b序列到位置j的子序列数目

if(a[i]!=b[j]) dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]  

当前a[i]!=b[j] 那么需要继承[1,i]与[1,j-1]的相同子序列数目,同理[1,i-1]与[1,j]也需要继承。但是在继承的时候,多算了[1,i-1]与[1,j-1]的,仔细看看前面的[i-1,j] && [i,j-1]都包含了[i-1,j-1],所以会多算一次,减去就可以了

if(a[i]==b[j]) dp[i][j]=dp[i-1][j]+dp[i][j-1]+1

和前面一样,先不考虑a[i]与b[j]的关系,统计之前的值并继承。dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1],现在来考虑a[i]==b[j]对当前[i,j]的贡献,前面提到了[i-1,j-1]算加了两次,要减掉一次。

这里需要把a[i]这个元素加到一次的[i-1,j-1]上去 ,使得前面的相同子序列用上a[i],然后就有dp[i-1][j-1]次,加上就可以了,至于为什么+1,显然{ a[i] & b[j] }可以单独做一个子序列啊。来组数据模拟一下吧

a:1 2 3 4 5

b:1 3 4 5 1

假设当前枚举到:[4,3] 且a[4]==b[3]

a=1 2 3 4

b=1 3 4

dp[4][3]=dp[4][2]+dp[3][3]  (当前没有考虑a[4]==b[3]进去

dp[4][2]&dp[3][3],当前对应的子序列为:{a=1,b=1}、{a=3,b=3}、{a=1,3 , b=1,3 }  & {a=1,b=1}、{a=3,b=3}、{a=1,3 , b=1,3 }

显然多算了一次dp[3][2],那么我在多算的这dp[3][2]三次里面加上一个元素a[4]:

{a=1,b=1}、{a=3,b=3}、{a=1,3 , b=1,3 }  & {a=1,4 , b=1,4 }、{a=3,4 , b=3,4 }、{a=1,3,4 , b=1,3,4 }

所以不需要减去dp[3][2],后面+1 -> 子序列{4,4}


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 1e9
const ll mod=1000000007;
using namespace std;
int n,m;
ll dp[1010][1010];
int a[1010],b[1010];
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=m;i++) scanf("%d",&b[i]);
        mst(dp,0);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i]==b[j])
                    dp[i][j]=(dp[i-1][j]+dp[i][j-1]+1)%mod;
                else dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;
                dp[i][j]%=mod;
            }
        }
        printf("%I64d\n",(dp[n][m]%mod+mod)%mod);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值