codeforces796E Exam Cheating

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

题目链接:CF796E

正解:$DP$

解题报告:

  考虑用$f[i][j][x][y]$表示考虑完前$i$个问题,当前总共用了$j$次机会,对于第一个人还能看$x$道题,第二个人还能看$y$道题的最优值,考虑$x$和$y$等于$0$的情况,直接转移就好了。

  这里写转出可能会方便一些。

  注意到这个复杂度是$O(npk^2)$的,但是当$p>\frac{2*n}{k}$时,可以全选,那么直接全选就好了,特判一下,所以复杂度是$O(n^2k)$。

 

//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <ctime>
#define lc root<<1
#define rc root<<1|1
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define reg(i,x) for(int i=first[x];i;i=next[i])
using namespace std;
typedef long long LL;
const int MAXN = 1002;
int n,p,k,a[MAXN],b[MAXN],ans;
int n1,n2,f[2][MAXN][52][52];
//f[i][j][x][y]表示考虑完前i个问题,当前总共用了j次机会,第一个人还能看x道题,第二个人还能看y道题的最优值
inline void upd(int &x,int y){ if(y>x) x=y; }
inline int getint() {
    int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}

inline void work(){
	n=getint(); p=getint(); k=getint();
	n1=getint(); for(int i=1;i<=n1;i++) a[getint()]++;
	n2=getint(); for(int i=1;i<=n2;i++) b[getint()]++;
	int lim=n/p; if(n%p!=0) lim++; lim<<=1;
	if(k>=lim) {
		//printf("%d",n1+n2); 
		for(int i=1;i<=n;i++) ans+=a[i]|b[i];
		printf("%d",ans);
		return ; 
	}

	memset(f,-0x3f,sizeof(f));

	f[0][0][0][0]=0; int to,tag=1;
	for(int i=1/*!!!*/;i<=n;i++) {
		to=tag; memset(f[to],-0x3f,sizeof(f[to]));//!!!
		tag^=1;
		for(int j=0;j<=p;j++) {
			for(int ii=0;ii<=k;ii++) {
				for(int jj=0;jj<=k;jj++) {
					if(!ii && !jj) {
						upd(f[to][j][0][0],f[tag][j][0][0]);
						upd(f[to][j+1][k-1][0],f[tag][j][0][0]+a[i]);
						upd(f[to][j+1][0][k-1],f[tag][j][0][0]+b[i]);
						upd(f[to][j+2][k-1][k-1],f[tag][j][0][0]+(a[i]|b[i]));
					}
					else if(!ii) {
						upd(f[to][j][0][jj-1],f[tag][j][0][jj]+b[i]);
						upd(f[to][j+1][k-1][jj-1],f[tag][j][0][jj]+(a[i]|b[i]));
						upd(f[to][j+2][k-1][k-1],f[tag][j][0][jj]+(a[i]|b[i]));
					}
					else if(!jj) {
						upd(f[to][j][ii-1][0],f[tag][j][ii][0]+a[i]/*!!!*/);
						upd(f[to][j+1][ii-1][k-1],f[tag][j][ii][0]+(a[i]|b[i]));
						upd(f[to][j+2][k-1][k-1],f[tag][j][ii][0]+(a[i]|b[i]));
					}
					else upd(f[to][j][ii-1][jj-1],f[tag][j][ii][jj]+(a[i]|b[i]));
				}
			}
		}
	}
	tag^=1;
	for(int l=0;l<=p;l++)
		for(int i=0;i<=k;i++)
			for(int j=0;j<=k;j++)
				ans=max(ans,f[tag][l][i][j]);
	printf("%d",ans);
 }

int main()
{
#ifndef ONLINE_JUDGE
	freopen("796.in","r",stdin);
	freopen("796.out","w",stdout);
#endif
    work();
    return 0;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

posted @ 2017-04-12 14:34  ljh_2000  阅读(889)  评论(0编辑  收藏  举报