状压DP
先预处理出来pre[i][S]表示对于第i个位置,往后5个的状态是S时,开心的小朋友的数量。
然后dp的时先枚举前5个的状态,再dp。
因为围栏是环状的,之后统计答案时统计的是那个f[n][S]=startS的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int n,m,hsta,lsta,pre[10005][33],f[10005][33],cnt; void Dfs(int E,int dep,int sta) { if(dep==5) { if(sta&lsta||(sta&hsta)!=hsta) pre[E][sta]++; return; } Dfs(E,dep+1,sta|(1<<dep)); Dfs(E,dep+1,sta); } int main() { scanf("%d%d",&m,&n); for(int i=1,e,h,l,x;i<=n;i++) { scanf("%d%d%d",&e,&h,&l); hsta=lsta=0; while(h--) scanf("%d",&x),x=(x-e+m)%m,hsta|=(1<<x); while(l--) scanf("%d",&x),x=(x-e+m)%m,lsta|=(1<<x); Dfs(e,0,0); } int ans=0; for(int S=0;S<32;S++) { memset(f[0],0xcf,sizeof f[0]); f[0][S]=0; for(int i=1;i<=m;i++) for(int j=0;j<32;j++) f[i][j]=max(f[i-1][(j&15)<<1],f[i-1][(j&15)<<1|1])+pre[i][j]; ans=max(ans,f[m][S]); } cout<<ans<<endl; return 0; }