CodeForces - 1481E Sorting Books(贪心+dp)
題目鏈接:點擊查看
題目大意:給出一個長度為 nnn 的序列,每次操作可以將任意一本書放到序列的末尾,問最少需要操作多少次,才能使得相同的數字挨在一起
題目分析:不難看出,對每個位置的數都操作一次,是肯定能滿足條件的,現在我們的目標是如何求得最優解
我們需要先轉換一下模型,題目要求操作最少,我們可以轉換為求哪些位置是不需要移動的。這樣將剩下的位置按照一定次序進行操作,一定是可以達到目標的
對于某個數字 xxx 而言,設 l[x]l[x]l[x] 和 r[x]r[x]r[x] 分別為 xxx 在原序列中第一次和最后一次出現的位置,同時 cnt[x]cnt[x]cnt[x] 是 xxx 在整個序列出現的次數。假如 xxx 不需要移動的話,那么 [l[x],r[x]][l[x],r[x]][l[x],r[x]] 這個區間內對 dpdpdp (哪些位置不需要移動)可以提供 cnt[x]cnt[x]cnt[x] 的貢獻
不難看出,經過一系列迭代后,可以同時做出貢獻的區間,必須是互不相交的,這一點是比較顯然的
所以我們可以參考區間覆蓋類 dpdpdp 的轉移框架:dp[i]=dp[j]+[j,i]區間的貢獻dp[i]=dp[j]+[j,i]區間的貢獻dp[i]=dp[j]+[j,i]區間的貢獻
分析到此為止,本題其實就是一個中規中矩的 dpdpdp 而已,下面我想加入點自己的理解
如果繼續下去,dpdpdp 的狀態意義為,哪些位置是不需要移動的位置,那么我們必須限制遞推是倒著來的,也就是 dp[i]dp[i]dp[i] 代表的是,區間 [i,n][i,n][i,n] 中,最多有多少個位置是不需要移動的
為什么要倒著來呢?因為本題的操作是需要將數字扔到序列的末尾,dp[i]dp[i]dp[i] 可以初始化為,[i,n][i,n][i,n] 中有多少個 a[i]a[i]a[i],這樣初始化是很簡單且可行的,可行性自己思考一下就能想明白了。但是與之相對的,如果 dp[i]dp[i]dp[i] 的遞推是正向進行的,那就無法這樣初始化了,所以遞推下去相對困難
所以可以正著來嗎?答案是肯定的,只不過需要對 dpdpdp 狀態換個意義了,dp[i]dp[i]dp[i] 代表的是 [1,i][1,i][1,i] 中,每個數字所在的范圍互不相交可以取到的最多的數字。如果想要求解上述的 “最多有多少個位置是不需要移動的”,還需要做進一步的轉換,那就是需要求出區間 [i+1,n][i+1,n][i+1,n] 中,出現次數最多的數字。因為根據貪心來想,我們如果想要讓 dp[i]dp[i]dp[i] 前面的部分作出貢獻,就必須在 [i+1,n][i+1,n][i+1,n] 這段區間中固定下來一個 “不需要移動的數字” 才行。
其實也比較好理解,根據區間不相交的特點,dp[i]dp[i]dp[i] 已經求出了 [1,i][1,i][1,i] 中不需要移動的數字了,而我們還需要求出 [i+1,n][i+1,n][i+1,n] 中不需要移動的數字,貪心去想,顯然是令出現次數最多的數字不動是最優的
代碼:
倒著的
正著的:
// Problem: E. Sorting Books // Contest: Codeforces - Codeforces Round #699 (Div. 2) // URL: https://codeforces.com/contest/1481/problem/E // Memory Limit: 256 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #define lowbit(x) x&-x using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; int a[N],dp[N],l[N],r[N],cnt[N],mmax[N]; int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n;read(n);for(int i=1;i<=n;i++) {read(a[i]);r[a[i]]=i;if(l[a[i]]==0) {l[a[i]]=i;}}for(int i=n;i>=1;i--) {cnt[a[i]]++;mmax[i]=max(mmax[i+1],cnt[a[i]]);}int ans=0;for(int i=1;i<=n;i++) {dp[i]=dp[i-1];if(i==r[a[i]]) {dp[i]=max(dp[i],dp[l[a[i]]-1]+cnt[a[i]]);}ans=max(ans,dp[i]+mmax[i+1]);}cout<<n-ans<<endl;return 0; }總結
以上是生活随笔為你收集整理的CodeForces - 1481E Sorting Books(贪心+dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1480D2
- 下一篇: CodeForces - 1550E S