UVA 11775 Unique Story(LCS [LIS] + BIT)

本文介绍了一种计算两个序列中相同子序列数量的方法,提供了三种不同复杂度的算法实现,分别是O(nmlognlogm)、O(nm)和O(nlogn)。这些方法利用了动态规划、LIS转化等技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

,n1000

分析:

,dp,dp[i][j]:=a[i],b[j]
,,
,(2n+2m2),

这里写图片描述


O(nmlognlogm)

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,j1)+sum(i1,j)sum(i1,j1)+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 << endl
const 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;
}

O(nm)

,,
2. dp[i][j]:=a[i],b[j]
a[i]==b[j],+a[i],b[j]+a[i],b[j]
dp[i][j]=2dp[i1][j1]+2
a[i]!=b[j],,(i,j)
dp[i][j]=dp[i][j1]+dp[i1][j]dp[i1][j1]
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 << endl
const 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;
}

O(nlogn)

LCSLIS
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 << endl
const 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值