题解:P11427 [清华集训 2024] 绝顶之战
ini2015_____ · · 题解
我们注意到一个题目是非多项式复杂度是这个题目 ini 不会的充分条件 /kk。
首先一个观察是,如果我选择集合
所以我们对于一个集合能否被放进去,我们只需要知道放进去这个集合能占据的最大长度
然后你可能会设计一个状态是我考虑
这个状态设计问题在于,假如我当前
所以你发现能放进去的集合和不能放进去的集合的交集并非全集,你的状态就是
转移的时候考虑如果
如果
如果
状态数是
然后你怎么处理这里的
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define chkmax(a,b) a=max(a,b)
using namespace std;
mt19937_64 rnd(time(0));
inline char gc() {
constexpr int S=1<<23;
static char buf[S],*p1=buf,*p2=buf;
return (p1==p2&&(p2=(p1=buf)+fread(buf,1,S,stdin),p1==p2)?EOF:*p1++);
}
inline int read() {
int a=0,b=0;char c=gc();
while(c<'0'||c>'9')b^=(c=='-'),c=gc();
while(c>='0'&&c<='9')a=a*10-48+c,c=gc();
return b?-a:a;
}
const int N=14,inf=1e18+7;
int n,m,s;
int a[N];
int sum[1<<N];
vector<int> ans;
unordered_map<int,int> f[N][1<<N];
int dp(int p,int S,int T){
if(p==n)return inf;
if((T>>p&1)&&(a[p]<=sum[S]))return -inf;
if(f[p][S].find(T)!=f[p][S].end())return f[p][S][T];
int res=0;
if(S>>p&1){
int nS=S^(1<<p),res=-inf;
for(int S1=nS;S1;S1=(S1-1)&nS)chkmax(res,a[p]+dp(p+1,S1,T)+dp(p+1,S1^nS,T));
chkmax(res,a[p]+dp(p+1,0,T)+dp(p+1,nS,T));
return f[p][S][T]=res;
}
if(T>>p&1)return f[p][S][T]=min(a[p],dp(p+1,S,T^(1<<p)));
return f[p][S][T]=dp(p+1,S,T);
}
signed main(){
m=read(),n=read(),s=1<<n;
for(int i=0;i<n;i++)a[i]=read();
for(int i=0;i<s;i++)for(int j=0;j<n;j++)if(i>>j&1)sum[i]+=a[j];
for(int i=0;i<s;i++)if(sum[i]<=m&&m<=dp(0,i,(s-1)^i))ans.pb(sum[i]);
sort(ans.begin(),ans.end()); ans.erase(unique(ans.begin(),ans.end()),ans.end());
printf("%d\n",(int)ans.size());
for(int v:ans)printf("%lld ",v);
return 0;
}
// Think twice,code once