专栏文章

P13341 题解

P13341题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minhb3p3
此快照首次捕获于
2025/12/02 02:24
3 个月前
此快照最后确认于
2025/12/02 02:24
3 个月前
查看原文
建议降蓝。
考虑如下构造:任取 1212 的约数 kk,以及 d12kd\ge \frac{12}{k}。找出 kdk\cdot d 个数,每 kk 个数分一段,一共 dd 段。然后找出 (d12k)\binom{d}{\frac{12}{k}} 个人,每个人从中选出 12k\frac{12}{k} 段,这样不重不漏地覆盖所有可能的选择情况。
例如当 k=4,d=5k=4,d=5 时,找出五个段 [0,3],[4,7],[8,11],[12,15],[16,19][0,3],[4,7],[8,11],[12,15],[16,19],每个人从中选出 33 段,一共十种选择,对应十个人。
容易证明这种构造满足条件。并且我们可以把多个这样的结构拼在一起——只需要保证它们使用的数互不相同即可。
找出所有可能的构造,使用动态规划把它们组合在一起即可。
CPP
#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;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...