Luogu P3622 [APIO2007]动物园

题目

显然环是比较难处理的,我们不妨把环断成链,然后先忽略掉所有从n跑到1的情况.

那么很容易定义出这样的状态 f [ i ] [ j ] f[i][j] 表示前 i i 个位置最后4个位置的删除状态为 j j (状态压缩)的最大方案数,然后每扫过一个人观测范围的终点就统计一下:

{ f [ i ] [ ( j & 7 ) 2 ] = max ( f [ i 1 ] [ j ] + c a l c ( i , j 2 ) f [ i ] [ ( j & 7 ) 2 + 1 ] = max ( f [ i 1 ] [ j ] + c a l c ( i , j 2 + 1 ) ) \begin{cases} f[i][(j\& 7)*2]=\max(f[i-1][j]+calc(i,j*2)\\ f[i][(j\& 7)*2+1]=\max(f[i-1][j]+calc(i,j*2+1))\end{cases}

解释一下:上面状态压缩是赋予远端更大的2的次幂权重, c a l c ( x , y ) calc(x,y) 表示终点为 x x 状态为 y y 的可满足人数.

把环接上的话,我们就需要记录一下初始前4个位的状态,代码中定义 f [ i ] [ j ] [ k ] f[i][j][k] 表示前 i i 个位置 [ 1 , 4 ] [1,4] 的状态为 j j ,最后4为为 k k 的方案.

特别的,最后我们应该加上跨过 ( n , 1 ) (n,1) 的人数.

#include<bits/stdc++.h>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define fi first
#define se second
#define vi vector<int>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef unsigned ui;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=1e4+10,M=5e4+10,size=1<<20,mod=998244353;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

int n,m,f[N][16][16];
struct edge{int x,y,next;}a[M]; //x表示不喜欢的集合,y表示喜欢的集合 
int len,last[N];

void ins(int x,int u,int v) {
	a[++len]=(edge){u,v,last[x]};
	last[x]=len;
}

int calc(int x,ui y) {
	int s=0;
	for(int k=last[x];k;k=a[k].next) {
		ui u=a[k].x,v=a[k].y;
		if((y&u)||((~y)&v)) s++;
	}
	return s;
}

void upd(int &x,int y) {if(x<y) x=y;}

int g(int t) {
	int s=0;
	for(int i=1;i<=4;i++) {
		int y=t>>(4-i)&31;
		s+=calc(i,y);
	}
	return s;
}

int main() {
	qr(n); qr(m);
	memset(f[4],-63,sizeof f[4]);
	for(int i=0;i<16;i++) 
		f[4][i][i]=0;
	while(m--) {
		int x=0,y=0,i,j,u,v;
		qr(i); qr(u); qr(v);
		while(u--) qr(j),x|=1<<(4-(j>=i?j-i:j-i+n));
		while(v--) qr(j),y|=1<<(4-(j>=i?j-i:j-i+n));
		if(i+4>n) ins(i+4-n,x,y);
		else ins(i+4,x,y);
	}
	for(int i=5;i<=n;i++) 
		for(int k=0;k<16;k++) {//i前4个位置的状态 
			int a=calc(i,k*2),b=calc(i,k*2+1);//O(32m)
			for(int j=0;j<16;j++) {//[1,4]的状态 
				upd(f[i][j][(k&7)*2],f[i-1][j][k]+a);
				upd(f[i][j][(k&7)*2+1],f[i-1][j][k]+b);//O(256n)
			}
		}
	int ans=0;
	for(int j=0;j<16;j++)
		for(int k=0;k<16;k++) 
			upd(ans,f[n][j][k]+g(k*16|j));
	pr2(ans);
	return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/106692142