[IOI2007]Miners
阿新 • • 發佈:2018-08-19
n) std 長度 ner == limits reg 收益 給定
[IOI2007]Miners
題目大意:
兩個人吃東西,總共有\(3\)種食物,每個人每次吃到食物時可以獲得的收益是當前食物和前兩次吃的食物中,不同食物的種數。現在給定一個長度為\(n(n\le10^5)\)的食物序列,按順序每次將這些食物分配給兩個人中的一個。問收益總和的最大值。
思路:
\(f[i][j][k][l][m]\)表示分完前\(i\)個吃的,\(A\)最後兩個吃了\(i\)和\(j\),\(B\)最後兩個吃了\(l\)和\(m\)時的最大收益。
時間復雜度\(\mathcal O(4^4n)\)。
為了防止MLE需要使用滾動數組。
源代碼:
#include<cstdio> #include<cctype> #include<climits> #include<algorithm> inline int getint() { register char ch; while(!isdigit(ch=getchar())); register int x=ch^'0'; while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); return x; } inline int getfood() { register char ch; while(!isalpha(ch=getchar())); if(ch=='M') return 1; if(ch=='F') return 2; if(ch=='B') return 3; return 0; } const int N=1e5+1; int f[2][4][4][4][4]; inline void up(int &x,const int &y) { x=std::max(x,y); } inline int calc(int x,int y,const int &z) { x=x?:z; y=y?:z; if(x==y&&y==z) return 1; if(x==y&&y!=z) return 2; if(x==z&&z!=y) return 2; if(y==z&&x!=y) return 2; return 3; } int main() { const int n=getint(); for(register int j=0;j<4;j++) { for(register int k=0;k<4;k++) { for(register int l=0;l<4;l++) { for(register int m=0;m<4;m++) { f[0][j][k][l][m]=INT_MIN; } } } } f[0][0][0][0][0]=0; for(register int i=1;i<=n;i++) { const bool cur=i&1; const int x=getfood(); for(register int j=0;j<4;j++) { for(register int k=0;k<4;k++) { for(register int l=0;l<4;l++) { for(register int m=0;m<4;m++) { f[cur][j][k][l][m]=INT_MIN; } } } } for(register int j=0;j<4;j++) { for(register int k=0;k<4;k++) { for(register int l=0;l<4;l++) { for(register int m=0;m<4;m++) { if(f[cur^1][j][k][l][m]==INT_MIN) continue; up(f[cur][k][x][l][m],f[cur^1][j][k][l][m]+calc(j,k,x)); up(f[cur][j][k][m][x],f[cur^1][j][k][l][m]+calc(l,m,x)); } } } } } int ans=0; for(register int j=0;j<4;j++) { for(register int k=0;k<4;k++) { for(register int l=0;l<4;l++) { for(register int m=0;m<4;m++) { up(ans,f[n&1][j][k][l][m]); } } } } printf("%d\n",ans); return 0; }
[IOI2007]Miners