Codeforces 645E. Intellectual Inquiry(DP,貪心)
阿新 • • 發佈:2018-10-13
type ack math har long tdi std turn priority
Codeforces 645E. Intellectual Inquiry
題意:給定一串字符,由前k個小寫拉丁字母組成,要求在該字符串後面補上n個字符(也從前k個小寫拉丁字母裏面選),使得最後得到的字符串含有本質不同的子序列的數量最大。
思路:要解決這個問題,首先要解決如何求字符串本質不同的子序列的個數的問題。定義dp[i][j]表示前i個字符內,以字符j結尾的本質不同的子序列的個數。那麽可推得轉移式:s[i]==j時,dp[i][j] = \(\sum_{t=1}^{k}dp[i-1][t]\) +1 (s[i]可自成一個子序列,故+1);s[i]!=j時,則dp[i][j]=dp[i-1][j].則最後答案為 \(\sum_{t=1}^{k}dp[len][t]\) 。接下來解決補n個字符的問題,觀察dp轉移式可以發現,每次會把 \(\sum_{t=1}^{k}dp[i-1][t]\) +1 賦給dp[i][s[i]],其余的則直接賦dp[i-1]對應的值,保持不變。因此要想使最後的答案最大,每次應該給最小的dp[i][j]賦值,因此後面的n個字符,每次都要填當前dp值最小的那個字符,而觀察可知那個字符一定是最後出現位置最靠前的那個,因為dp值是遞增的,越遲出現值一定越大。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<map> #include<queue> #include<string> #include<vector> #include<cmath> #include<climits> #include<functional> #include<set> #define dd(x) cout<<#x<<" = "<<x<<" " #define de(x) cout<<#x<<" = "<<x<<endl #define fi first #define se second #define mp make_pair #define pb push_back using namespace std; typedef long long ll; typedef pair<int,int> P; typedef vector<int> V; typedef map<int,int> M; typedef queue<int> Q; typedef priority_queue<int> BQ; typedef priority_queue<int,vector<int>,greater<int> > SQ; const int maxn=1e6+10,INF=0x3f3f3f3f,mod=1e9+7; int dp[30],last[30]; char s[maxn<<1]; inline int add(int a,int b) { a+=b; if (a>=mod) a-=mod; return a; } int sum(int k) { int res=0; for (int i=0;i<k;++i) res=add(res,dp[i]); return res; } int main() { int n,k; scanf("%d%d%s",&n,&k,s+1); int m=strlen(s+1); for (int i=1;i<=m;++i) { int c=s[i]-‘a‘; dp[c]=sum(k)+1; last[c]=i; } for (int i=m+1;i<=m+n;++i) { int c=min_element(last,last+k)-last; dp[c]=sum(k)+1; last[c]=i; } printf("%d",add(sum(k),1)); return 0; }
Codeforces 645E. Intellectual Inquiry(DP,貪心)