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=1∑k(n−len(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了,我当时也没做出来, 题解也是弄得别人的, 莫怪