P13341 题解
建议降蓝。
考虑如下构造:任取
例如当
容易证明这种构造满足条件。并且我们可以把多个这样的结构拼在一起——只需要保证它们使用的数互不相同即可。
找出所有可能的构造,使用动态规划把它们组合在一起即可。
#include<bits/stdc++.h>
using namespace std;
#define ll int
const ll N=100;
int n,C[N][N],f[N],g[N],d[N],x[N],cnt[N],a[N];
void dfs(int A,int B,int k,int dif){
if (A<B||B<0){
return;
}
if (A==0){
for (int i=1;i<=(12/k);++i){
for (int j=0;j<k;++j){
cout<<dif+a[i]*k+j<<' ';
}
}
cout<<endl;
return;
}
dfs(A-1,B,k,dif);
a[B]=A-1;
dfs(A-1,B-1,k,dif);
}
void solve(int n,int dif){
if (n==0){
return;
}
// cout<<"solve "<<n<<' '<<g[n]<<endl;
int c=g[n];
dfs(cnt[c],12/x[c],x[c],dif);
solve(n-c,dif+d[c]);
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
for (int i=0;i<N;++i){
for (int j=C[i][0]=1;j<=i;++j){
C[i][j]=min(C[i-1][j]+C[i-1][j-1],N);
}
}
cnt[1]=1;d[1]=12;x[1]=12;
for (int k=1;k<12;++k){
if (12%k){
continue;
}
for (int o=12/k+1;o*k<=50;++o){
int c=C[o][12/k];
if (c>50){
break;
}
if (d[c]==0||d[c]>o*k){
d[c]=o*k;x[c]=k;cnt[c]=o;
}
}
}
for (int i=1;i<=50;++i){
f[i]=51;
}
for (int i=0;i<=50;++i){
// cout<<f[i]<<endl;
for (int j=1;i+j<=50;++j){
if (!d[j]){
continue;
}
if (f[i]+d[j]<f[i+j]){
f[i+j]=f[i]+d[j];
g[i+j]=j;
}
}
}
cin>>n;
solve(n,0);
return 0;
}