Codeforces 1110D Jongmah [DP]
阿新 • • 發佈:2019-02-08
esp define 做出 isp void new ont 三元組 www.
,得到轉移方程:
洛谷
Codeforces
我…我我把這…這這題切了???
說實話這題的確不難,只是我看到有大佬沒做出來有點慌……
突然發現這題是我在洛谷的第500個AC呢。那就更要寫篇題解紀念一下了。
思路
容易想到一個貪心:把有三個的都取完,然後隨便搞後面的。
這顯然是錯的……
但你進一步思考發現:對於三元組\(\{x-2,x-1,x\}\),它最多取\(2\)次,否則就可以變成多個\(\{x,x,x\}\)後再重新搞。
那麽就容易想到DP了。
設\(dp_{i,j,k}\)表示考慮到第\(i\)位,欽定第\(i\)位已經用掉了\(j\)個,第\(i-1\)位已經用掉了\(k\)個,能得到的三元組個數。
轉移時枚舉選幾個\(\{i-2,i-1,i\}\)
\[ dp_{i,j,k}=\max_{l=0}^2\{dp_{i-1,k+l,l}+\lfloor \frac{cnt_i-l-j}{3}\rfloor +l\} \]
最後\(ans=dp_{m,0,0}\)。
註意DP時一個位置會被欽定兩次,所以\(0\leq j,k\leq 4\)。
代碼
#include<bits/stdc++.h> namespace my_std{ using namespace std; #define pii pair<int,int> #define fir first #define sec second #define MP make_pair #define rep(i,x,y) for (int i=(x);i<=(y);i++) #define drep(i,x,y) for (int i=(x);i>=(y);i--) #define go(x) for (int i=head[x];i;i=edge[i].nxt) #define sz 1010101 typedef long long ll; template<typename T> inline void read(T& t) { t=0;char f=0,ch=getchar(); double d=0.1; while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar(); if(ch==‘.‘) { ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar(); } t=(f?-t:t); } template<typename T,typename... Args> inline void read(T& t,Args&... args){read(t); read(args...);} void file() { #ifndef ONLINE_JUDGE freopen("a.txt","r",stdin); #endif } // inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;} } using namespace my_std; int n,m; int cnt[sz]; int dp[sz][5][5]; int main() { file(); int x; read(n,m); rep(i,1,n) read(x),++cnt[x]; memset(dp,~0x3f,sizeof(dp)); dp[0][0][0]=0; rep(i,0,min(4,cnt[1])) dp[1][i][0]=(cnt[1]-i)/3; rep(i,2,m) { rep(j,0,4) { if (j>cnt[i]) break; rep(k,0,4) { if (k>cnt[i-1]) break; rep(l,0,2) { if (j+l>cnt[i]||k+l>cnt[i-1]||l>cnt[i-2]||k+l>4) break; dp[i][j][k]=max(dp[i][j][k],dp[i-1][k+l][l]+(cnt[i]-l-j)/3+l); } } } } cout<<dp[m][0][0]; }
Codeforces 1110D Jongmah [DP]