【CF525E】Anya and Cubes(meet in middle)

点此看题面

大致题意:(n)个数中选任意个数,并使其中至多(k)个数(x_i)变为(x_i!),求使这些数和为(S)的方案数。

(meet in middle)

这应该是(meet in middle)一道比较板子的题目。

我们先对于一半的数,爆搜然后开((k+1))(map)统计使用(!)个数小于等于(i),和为(j)的方案数。

然后对于另一半数,我们再爆搜一遍,到(map)中去找对应的情况使得使用(!)个数小于等于(k),和为(j)

并用一个变量(ans)统计答案。

由于一个数有选、不选、选做阶乘三种情况,所以时间复杂度为(O(3^{frac n2})),而且加上剪枝之后还跑不满,稳过。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define RL Reg LL
#define Con const
#define CI Con int&
#define CL Con LL&
#define I inline
#define W while
#define N 25
#define LL long long
using namespace std;
int n,m,k,a[N+5];LL s,ans,Fac[N+5];map<LL,int> p[N+5];
I void dfs1(CI x,CI u,CL v)//第一次dfs
{
	if(x>n/2) {for(RI i=u;i<=k;++i) ++p[i][v];return;}//用map存储该情况方案数
	dfs1(x+1,u,v),a[x]+v<=s&&(dfs1(x+1,u,a[x]+v),0),//不选/选
	a[x]<=m&&Fac[a[x]]+v<=s&&u<k&&(dfs1(x+1,u+1,Fac[a[x]]+v),0);//选做阶乘
}
I void dfs2(CI x,CI u,CL v)//第二遍dfs,除统计答案过程大体同上
{
	if(x>n) return (void)(ans+=p[k-u][s-v]);//统计答案
	dfs2(x+1,u,v),a[x]+v<=s&&(dfs2(x+1,u,a[x]+v),0),
	a[x]<=m&&Fac[a[x]]+v<=s&&u<k&&(dfs2(x+1,u+1,Fac[a[x]]+v),0);
}
int main()
{
	RI i;for(scanf("%d%d%lld",&n,&k,&s),i=1;i<=n;++i) scanf("%d",a+i);//读入
	for(Fac[0]=i=1;Fac[i-1]<=s;++i) Fac[i]=Fac[i-1]*i;m=i-1;//算阶乘
	return dfs1(1,0,0),dfs2(n/2+1,0,0),printf("%lld",ans),0;//求解并输出
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF525E.html