bzoj1151 动物园
Description
新建的圆形动物园是亚太地区的骄傲。圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围栏里有一 种动物。如下图所示:.png)

Input
输入的第一行包含两个整数N, C,用空格分隔。 N是围栏数(10≤N≤10 000),C是小朋友的个数(1≤C≤50 000)。 围栏按照顺时针的方向编号为1,2,3,…,N。 接下来的C行,每行描述一个小朋友的信息, 以下面的形式给出: E F L X1 X2 … XF Y1 Y2 … YL 其中: E表示这个小朋友可以看到的第一个围栏的编号(1≤E≤N), 换句话说,该小朋友可以看到的围栏为E, E+1, E+2, E+3, E+4。 注意,如果编号超过N将继续从1开始算。 如:当N=14, E=13时,这个小朋友可以看到的围栏为13,14,1, 2和3。 F表示该小朋友害怕的动物数。 L表示该小朋友喜欢的动物数。 围栏X1, X2, …, XF 中包含该小朋友害怕的动物。 围栏Y1, Y2, …, YL 中包含该小朋友喜欢的动物。 X1, X2, …, XF, Y1, Y2, …, YL是两两不同的整数, 而且所表示的围栏都是该小朋友可以看到的。 小朋友已经按照他们可以看到的第一个围栏的编号从小到大的顺序排好了 (这样最小的E对应的小朋友排在第一个,最大的E对应的小朋友排在最后一个)。 注意可能有多于一个小朋友对应的E是相同的。Output
仅输出一个数,表示最多可以让多少个小朋友高兴
Sample Input
10 101 1 1 3 2
2 1 0 4
3 1 1 5 6
4 1 1 7 6
5 1 0 6
6 1 2 9 8 10
7 1 0 10
8 1 0 8
9 1 1 1 2
10 1 0 2
Sample Output
10 把四个格压成一个状态。 能得到转移方程:dp[i][j]=max(dp[i-1][(j&15)<<1],dp[i-1][(j&15)<<1|1])+val[i][j]) 其中j&15就是放弃最高位,并枚举上一位是1还是0. val预处理很好理解。 然后就是这道题难点,处理环。 我们暴力枚举前五位,最后只取后五位和前五位相同的更新ans。#include#include #include #include #include #define in(a) a=read() #define REP(i,k,n) for(int i=k;i<=n;i++) using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } int n,m,a,u,v,ans=0; int p[6]={1,2,4,8,16,32}; int val[10010][32],dp[10010][32]; int main(){ in(n),in(m); REP(i,1,m){ in(a),in(u),in(v); int like=0,hate=0; REP(j,1,u) like|=p[(read()-a+n)%n]; REP(j,1,v) hate|=p[(read()-a+n)%n]; REP(j,0,31) if((like&j) || (hate&~j)) val[a][j]++; } REP(u,0,31){ REP(i,0,31) dp[0][i]=-2147483647; dp[0][u]=0; REP(i,1,n) REP(j,0,31) dp[i][j]=max(dp[i-1][(j&15)<<1],dp[i-1][(j&15)<<1|1])+val[i][j]; ans=max(ans,dp[n][u]); } printf("%d",ans); }