UVA11775 Unique Story dp+二维树状数组优化

先用map处理字符串每个元素,然后用数组储存

要求不相同的所有组合,我们反着来求

x = a(第一个字符串能构成的所有的组合序列)+b(第二个字符串能构成的所有的组合序列) - c(两个字符串中的相同组合序列)*2

a = 2^n(第一个字符串的元素个数)-1;同理b;(很煞笔的用组合公式求2333,后来反应过来也没有改了)

dp[i][j]代表以a字符串中的第i个元素为组合序列的最后一个元素,以b字符串中的第j个元素为组合序列的最后一个元素,相同组合序列的个数

sum[i][j]代表a字符串中前i个元素,b字符串中前j个元素,能构成的所有相同组合序列的个数之和

每次求得一个dp[i][j],就用去更新,树状数组

在利用树状数组求得sum[i][j]

/********************************************
Author         :Crystal
Created Time   :
File Name      :
********************************************/
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <sstream>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int ,int> pii;
#define MEM(a,b) memset(a,b,sizeof a)
#define CLR(a) memset(a,0,sizeof a);
const int inf = 0x3f3f3f3f;
const int MOD = 10000007;
//#define LOCAL
ll c[3001][3001];
int dp[2001][2001];
int sum[2001][2001];
int ans1[2001];
int ans2[2001];
int k1,k2;
void init(){
	for(int i=0;i<=2001;i++){
		//c[0][i] = 1;
		c[i][0] = 1;
	}
	for(int i=1;i<=2001;i++){
		for(int j=1;j<=i;j++){
			c[i][j] = (c[i][j] + c[i-1][j-1]+c[i-1][j])%MOD;
		}
	}
}
map<string,int> mp;
int cc[2001][2001], n; 
int Lowbit(int t)
    return t&(t^(t-1));
}
int Sum(int x,int y)
{
    ll sum = 0;
   	for(int i=x;i>0;i-=Lowbit(i)){
   		for(int j=y;j>0;j-=Lowbit(j)){
   			sum = (sum +cc[i][j])%MOD;
   		}
   	}
    return sum;
}
void add(int x, int y,int val)
{
    for(int i=x;i<=k1;i+=Lowbit(i)){
   		for(int j=y;j<=k2;j+=Lowbit(j)){
   			cc[i][j] = (val + cc[i][j])%MOD;
   		}
   	}
} 
int main()
{
#ifdef LOCAL
	freopen("in.txt", "r", stdin);
//	freopen("out.txt","w",stdout);
#endif
	init();
	int t;cin >> t;
	int kase = 1;
	while(t--){
		CLR(cc);
		CLR(sum);
		CLR(dp);
		mp.clear();
		char a[4001];
		char b[4001];
		scanf("%s%s",a,b);
		int la = strlen(a);
		int lb = strlen(b);
		int cnt = 0;
		k1 = 0;
		k2 = 0;
		for(int i=0;i<la;i++){
			string tmp;
			if(a[i] <= 'Z' && a[i] >= 'A'){
				tmp += a[i];
				while(i+1 <la && a[i+1] <= '9' && a[i+1] >= '0'){
					tmp += a[i+1];
					i++;
				}
				if(!mp[tmp]){
					mp[tmp] = ++cnt;
				}
				//cout << mp[tmp] << endl;
				ans1[++k1] = mp[tmp]; 
			}
		}
		for(int i=0;i<lb;i++){
			string tmp;
			if(b[i] <= 'Z' && b[i] >= 'A'){
				tmp += b[i];
				while(i+1<lb && b[i+1] <= '9' && b[i+1] >= '0'){
					tmp += b[i+1];
					i++;
				}
				if(!mp[tmp]){
					mp[tmp] = ++cnt;
				}
				ans2[++k2] = mp[tmp]; 
			}
		}
		n = k1*k2+k2;
		for(int i=1;i<=k1;i++){
			for(int j=1;j<=k2;j++){
				if(ans1[i]==ans2[j]){
					dp[i][j] = (dp[i][j]+sum[i-1][j-1]+1)%MOD;
					add(i,j,dp[i][j]);
				}
				sum[i][j] = Sum(i,j);
			}
		}
		ll ssum = 0;
		for(int i=1;i<=k1;i++){
			ssum = (c[k1][i]+ssum)%MOD;
		}
		for(int i=1;i<=k2;i++){
			ssum = (c[k2][i]+ssum)%MOD;
		}
		cout << "Case " << kase++ << ':' << ' ';
		cout << (ssum - sum[k1][k2]*2 +MOD*2)%MOD << endl;
	}
	return 0;
}










你可能感兴趣的:(dp,二维树状数组)