Codeforces Round #570 (Div. 3)-- Subsequences

Easy version :

题意:给定字符串s,数k, 求 m i n ( ∑ i = 1 k ( n − l e n ( i t h l e n s u b s t r i n g ) ) min(\sum_{i=1}^k (n - len(i_{th}lensubstring)) min(i=1k(nlen(ithlensubstring)) 且,substrings 不可重复, n是母串的长度。

可能我没说清楚

stragety: BFS ,数据还比较小

#include<bits/stdc++.h>
#include<bits/extc++.h>
#define oo INT_MAX
#define ll long long
#define db double
#define mp(a, b) make_pair(a, b)
#define met(a, b) memset(a, b, sizeof(a))
#define maxn 20005
#define _rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for(int i = (a); i >= (b); --i)
#define _for(i, a, b) for(int i = (a); i < (b) ;++i)
using namespace std;
using namespace __gnu_pbds;
gp_hash_table <int ,int> p;
int n;
int main() {
    ios::sync_with_stdio(0);
    int n, k;
    string s;
    cin >> n >> k >> s;
    int ans = 0;
    queue<string> q;
    set<string> st;
    
    q.push(s);
    st.insert(s);
    int len = n;
 
    while (!q.empty() && st.size() < k)   
    {
        string now = q.front();
        q.pop();
        _for(i, 0, now.size()){
            string nxt = now;
            nxt.erase(i, 1);
            if(st.count(nxt) || st.size() >= k)continue;
            st.insert(nxt);
            q.push(nxt);
            len += nxt.length();
        }
        
    }
    if(st.size() < k){
        ans = -1;
    }else{
        ans = n * k - len  ;
    }
    cout << ans << endl;
    // system("pause");
}


Hard version

题意同上, 但是数据变大了, BFS 会超时,

点我看数据

Stragety : dp

Firstly, let’s calculate the following auxiliary matrix: lsti,j means the maximum position pos that is less than or equal to i, and the character spos=j (in order from 0 to 25, ‘a’ = 0, ‘b’ = 1, and so on). It can be calculated naively or with some easy dynamic programming (initially all lsti,j are −1 and then for each i from 1 to n−1 all values lsti,j are equal to lsti−1,j except lsti,si which is i).

After calculating this matrix we can solve the problem by the following dynamic programming: let dpi,j be the number of subsequences of length j that ends exactly in the position i. Initially all values are zeros except dpi,1=1 for each i from 0 to n−1.

How do we perform transitionss? Let’s iterate over all lengths j from 2 to n, then let’s iterate over all positions i from 1 to n−1 in a nested loop, and for the current state dpi,j we can calculate it as ∑c=025dplsti−1,c,j−1. If lsti−1,c=−1 then we don’t need to add this state of the dynamic programming to the current state. Don’t forget to take the minimum with 1012 after each transition!

This transition means that we take all subsequences that end with each possible character of the alphabet and try to add the current character to each of them. You can understand that there are no overlapping subsequences in this dynamic programming.

After that let’s iterate over all possible lengths j from n to 1 and calculate the number of subsequences of the current length j. It equals to cnt=∑c=025dplstn−1,c,j. The same, if lstn−1,c=−1 then we don’t need to add this state of the dynamic programming to cnt. Don’t forget to take the minimum with 1012! If cnt≥k then let’s add k(n−len) to the answer and break the cycle. Otherwise let’s add cnt(n−len) to the answer and decrease k by cnt.

If after all iterations k is greater than zero then let’s try to add the empty string to the answer (we didn’t take it into account earlier). Increase the answer by n and decrease k by one. If after this k is still greater than zero then the answer is -1, otherwise the answer is the calculated sum.

简单来讲: 构造一个辅助矩阵last[i][j] 代表母串的前i个字符中,字符 S p o s = j S_{pos} = j Spos=j (in order from 0 to 25, ‘a’ = 0, ‘b’ = 1, and so on) 最后出现的位置, 然后构造dp[i][j] 代表以字符位置i结尾,长度等于j的字符串的个数, 最后按长度累加

Time complexity: O(n2).

#include<bits/stdc++.h>
#include<bits/extc++.h>
// #define oo INT_MAX
#define maxn 10000009 
#define _rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for(int i = (a); i >= (b); --i)
#define _for(i, a, b) for(int i = (a); i < (b) ;++i)
#define _rof(i, a, b) for(int i = (a); i > (b); --i)
#define ll long long
#define db double
#define met(a, b) memset(a, b, sizeof(a))
using namespace std;
using namespace __gnu_pbds;
ll oo = 1e12;
int main(){
	ios::sync_with_stdio(0);
	ll n, k;
	cin >> n >> k;
	k--;
	string s;
	cin >> s;
	vector<vector<int> > last(n + 1, vector<int>(26, -1));
	_for(i, 0, n){
		_for(j, 0, 26){
			if(i > 0) last[i][j] = last[i - 1][j];
		}
		last[i][s[i] - 'a'] = i;
	}
	vector<vector<ll> > dp(n + 1, vector<ll>(n + 1));
	_rep(i, 0, n){
		dp[i][1] = 1;
	}
	_for(len, 2, n){
		_for(i, 1, n){
			_for(j, 0, 26){
				if(last[i - 1][j] != -1){
					dp[i][len] = min(oo, dp[i][len] + dp[last[i - 1][j]][len - 1]);		
				}
			}
		}
	}
	ll ans = 0;
	_rof(len, n - 1, 0){//for each length
		ll cnt = 0;
		_for(j, 0, 26){
			if(last[n - 1][j] != -1){
				cnt += dp[last[n - 1][j]][len];
			}
		}
		if(cnt < k){
			ans += cnt * (n - len);
			k -= cnt;
		}else{
			ans += k * (n - len);
			k = 0;
			break;
		}
	}
	if(k == 1){// adding an empty string 
		ans += n;
		k = 0;
	}
	if(k > 0)ans = -1;
	
	cout << ans << endl;
	//system("pause");
}

##这个算是很难的dp了,我当时也没做出来, 题解也是弄得别人的, 莫怪

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值