UVA 11775 Unique Story(LCS [LIS] + BIT)
来源:互联网 发布:金蝶免费进销存软件 编辑:程序博客网 时间:2024/05/19 19:32
题意:
求两个序列不相同的序列个数,n≤1000
分析:
−−我直接正着搞,dp状态很显然,dp[i][j]:=以a[i],b[j]结尾的不相同的序列个数
但事实上非常难转移,存在重复的情况,搞了昨晚一个晚上也没解决
如果反正思考的话,考虑总子序列数(2n+2m−2)减去相同的子序列数,这个题就变得非常显然和简单了
1. 考虑dp[i][j]:=以a[i],b[j]结尾的相同的子序列的个数
转移只有一种当a[i]==b[j]时,dp[i][j]=∑dp[x][y](x<i,y<j)+2
这个二维的前缀和,我们可以用二维树状数组来优化就好了
dp[i][j]=sum(i,j−1)+sum(i−1,j)−sum(i−1,j−1)+2,就是去掉右下角的(i,j)这个点
ans相同的子序列个数=sum(n,m)
复杂度为O(nmlognlogm)
代码:
//// Created by TaoSama on 2015-11-22// Copyright (c) 2015 TaoSama. All rights reserved.////#pragma comment(linker, "/STACK:1024000000,1024000000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <vector>using namespace std;#define pr(x) cout << #x << " = " << x << " "#define prln(x) cout << #x << " = " << x << endlconst int N = 2e3 + 10, INF = 0x3f3f3f3f, MOD = 10000007;int n, m, u[N], v[N];int b[N][N], dp[N][N];void add(int &x, int y) { x = x + y + MOD; while(x >= MOD) x -= MOD;}void add(int x, int y, int v) { for(int i = x; i <= n; i += i & -i) for(int j = y; j <= m; j += j & -j) add(b[i][j], v);}int sum(int x, int y) { int ret = 0; for(int i = x; i; i -= i & -i) for(int j = y; j; j -= j & -j) add(ret, b[i][j]); return ret;}int cnt = 0;map<string, int> mp;int ID(string &s) { if(mp.count(s)) return mp[s]; mp[s] = ++cnt; return cnt;}void handle(int &n, string &s, int *u) { n = 0; s += 'A'; string tmp; for(int i = 0; i < s.size(); ++i) { if(isalpha(s[i])) { if(tmp.size()) { u[++n] = ID(tmp); tmp.clear(); } } tmp += s[i]; }}int two[2005] = {1};string s, t;int main() {#ifdef LOCAL freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);#endif ios_base::sync_with_stdio(0); int T; cin >> T; int kase = 0; for(int i = 1; i <= 2000; ++i) two[i] = two[i - 1] * 2 % MOD; while(T--) { cin >> s >> t; cnt = 0; mp.clear(); handle(n, s, u); handle(m, t, v); memset(dp, 0, sizeof dp); memset(b, 0, sizeof b); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(u[i] != v[j]) continue; add(dp[i][j], sum(i, j - 1) + sum(i - 1, j) - sum(i - 1, j - 1) + 2); add(i, j, dp[i][j]); } } int ans = ((two[n] + two[m] - 2 - sum(n, m)) % MOD + MOD) % MOD; printf("Case %d: %d\n", ++kase, ans); } return 0;}
仔细想想,其实我们可以把前缀和过程直接放在转移里,只要换一下状态
2. 考虑dp[i][j]:=处理到a[i],b[j]的相同的子序列的个数
a[i]==b[j],之前的+之前的加上a[i],b[j]+只有a[i],b[j]
dp[i][j]=2∗dp[i−1][j−1]+2
a[i]!=b[j],把之前所有的加起来,其实就是去掉(i,j)那个点的和上面的一样
dp[i][j]=dp[i][j−1]+dp[i−1][j]−dp[i−1][j−1]
ans相同的子序列个数=dp[n][m]
复杂度为O(nm)
代码:
//// Created by TaoSama on 2015-11-22// Copyright (c) 2015 TaoSama. All rights reserved.////#pragma comment(linker, "/STACK:1024000000,1024000000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <vector>using namespace std;#define pr(x) cout << #x << " = " << x << " "#define prln(x) cout << #x << " = " << x << endlconst int N = 2e3 + 10, INF = 0x3f3f3f3f, MOD = 10000007;int n, m, u[N], v[N];int b[N][N], dp[N][N];void add(int &x, int y) { x = x + y + MOD; while(x >= MOD) x -= MOD;}int cnt = 0;map<string, int> mp;int ID(string &s) { if(mp.count(s)) return mp[s]; mp[s] = ++cnt; return cnt;}void handle(int &n, string &s, int *u) { n = 0; s += 'A'; string tmp; for(int i = 0; i < s.size(); ++i) { if(isalpha(s[i])) { if(tmp.size()) { u[++n] = ID(tmp); tmp.clear(); } } tmp += s[i]; }}int two[2005] = {1};string s, t;int main() {#ifdef LOCAL freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);#endif ios_base::sync_with_stdio(0); int T; cin >> T; int kase = 0; for(int i = 1; i <= 2000; ++i) two[i] = two[i - 1] * 2 % MOD; while(T--) { cin >> s >> t; cnt = 0; mp.clear(); handle(n, s, u); handle(m, t, v); memset(dp, 0, sizeof dp); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(u[i] == v[j]) add(dp[i][j], 2 * dp[i - 1][j - 1] + 2); else add(dp[i][j], dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1]); } } int ans = ((two[n] + two[m] - 2 - dp[n][m]) % MOD + MOD) % MOD; printf("Case %d: %d\n", ++kase, ans); } return 0;}
这里就用到LCS和LIS的转化关系了
考虑a[i],b[j]相同的连一条边,如果是公共子序列的话,我们发现边不会交叉,我们可以很惊喜的发现这就是LIS了,问题由二维变成了一维
3. 考虑dp[i]:=以a[i]结尾上升子序列个数
BIT优化下转移过程就好了
ans相同的子序列个数=∑ni=1dp[i]
复杂度为O(nlogn)
代码:
//// Created by TaoSama on 2015-11-22// Copyright (c) 2015 TaoSama. All rights reserved.////#pragma comment(linker, "/STACK:1024000000,1024000000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <vector>using namespace std;#define pr(x) cout << #x << " = " << x << " "#define prln(x) cout << #x << " = " << x << endlconst int N = 2e3 + 10, INF = 0x3f3f3f3f, MOD = 10000007;int n, m, c, a[N];int b[N], dp[N];int cnt = 0;map<string, int> mp;int ID(string &s) { if(mp.count(s)) return mp[s]; mp[s] = ++cnt; return -1;}void add(int &x, int y) { x += y; if(x < 0) x += MOD; else if(x >= MOD) x -= MOD;}void update(int i, int v) { for(; i <= cnt; i += i & -i) add(b[i], v);}int sum(int i) { int ret = 0; for(; i; i -= i & -i) add(ret, b[i]); return ret;}void handle(int &n, string &s, bool flag) { n = c = 0; s += 'A'; string tmp; tmp += s[0]; for(int i = 1; i < s.size(); ++i) { if(isalpha(s[i])) { ++n; int id = ID(tmp); if(flag && ~id) a[++c] = id; tmp.clear(); } tmp += s[i]; }}int two[2005] = {1};string s, t;int main() {#ifdef LOCAL freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);#endif// ios_base::sync_with_stdio(0); int T; cin >> T; int kase = 0; for(int i = 1; i <= 2000; ++i) two[i] = two[i - 1] * 2 % MOD; while(T--) { cin >> s >> t; cnt = 0; mp.clear(); handle(n, s, false); handle(m, t, true); memset(dp, 0, sizeof dp); memset(b, 0, sizeof b); for(int i = 1; i <= c; ++i) { dp[i] = sum(a[i]) + 1; update(a[i], dp[i]); } int ans = ((two[n] + two[m] - 2 - 2 * sum(cnt)) % MOD + MOD) % MOD; printf("Case %d: %d\n", ++kase, ans); } return 0;}
- UVA 11775 Unique Story(LCS [LIS] + BIT)
- UVa 11775 Unique Story
- UVA 11775 Unique Story(DP)
- Uva 10635 王子和公主(LCS转LIS+二分)
- Uva - 10635 - Prince and Princess(LCS转LIS)
- UVA - 10635 - Prince and Princess (LCS转化为LIS)
- UVA 10635 - Prince and Princess ( LCS 转换为LIS )
- UVa 10635 - Prince and Princess(LCS转LIS)
- uva 10635 Prince and Princess(LCS转LIS~)
- UVA 10635 Prince and Princess lcs--》lis
- LCS,LIS(王子和公主,uva 10635)
- UVA-10635 LCS转化为LIS
- 子序列(LIS、LCS)
- bzoj 4990(LCS->LIS)
- dp(LCS转化成LIS)uva 10635 - Prince and Princess
- uva 10635 Prince and Princess(LCS问题转化成LIS问题O(nlogn))
- UVa 10635(lcs转lis优化模板)王子和公主
- LCS && LIS
- 电路定理
- PAGE_FAULT_IN_NONPAGED_AREA解决
- 关于cocoapods安装
- zoj 3010 The Lamp Game
- Objective C定义私有方法
- UVA 11775 Unique Story(LCS [LIS] + BIT)
- Location 服务问题纪录
- traincascade.cpp
- mac安装/升级java并配置环境变量
- 【南大软院大神养成计划:第八天】Sublime Text信仰初养成(一)
- Android.mk的用法和基础
- opencv学习笔记-线性空间滤波
- Android基础学-1
- 面试之C++题目汇总