题解 P3943 【星空】
题目链接
传送门
solution
挺考验思维的一道题,考场上猜了各种假贪心居然水过了32分
考虑这道题目中困扰我们的地方:
- 1.对区间取反
容易想到用差分思想,
- 2.有多种取反方式
事实上,对一段区间
- 原序列中每一个1最多导致现在的问题中多出2个点,于是最多有16个点,状压DP即可
code
#include<bits/stdc++.h> using namespace std; const int N=80010; int n,k,m,t[N],b[N],dis[N],dp[N],p[N],cnt,sum; int main(){ scanf("%d%d%d",&n,&k,&m); for(int i=1;i<=k;++i){ int x;scanf("%d",&x); t[x]^=1;t[x+1]^=1; } for(int i=1;i<=n+1;++i) if(t[i]) p[cnt++]=i; sum=(1<<cnt); for(int i=1;i<=m;++i) scanf("%d",&b[i]); memset(dis,0x3f,sizeof(dis));dis[0]=0; for(int i=1;i<=m;++i) for(int j=b[i];j<=n;++j) dis[j]=min(dis[j],dis[j-b[i]]+1); for(int i=1;i<=m;++i) for(int j=n-b[i];j>=0;--j) dis[j]=min(dis[j],dis[j+b[i]]+1); memset(dp,0x3f,sizeof(dp));dp[0]=0; for(int i=0;i<sum;++i) for(int j=0;j<cnt;++j) if(!(i&(1<<j))) for(int k=j+1;k<cnt;++k) if(!(i&(1<<k))) dp[i^(1<<j)^(1<<k)]=min(dp[i^(1<<j)^(1<<k)],dp[i]+dis[p[k]-p[j]]); printf("%d\n",dp[sum-1]); return 0; }