【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;//求解并输出
}
待到再迷茫时回头望,所有脚印会发出光芒