状压$dp$:
本蒟蒻被动规虐的死去活来,于是决定死磕$dp$了!以前看到$dp$立刻走人。。
这篇文章可能对新手不太友好,二进制这种我就不讲了,主要是为了方便自己记忆(对不起$qwq$)
进入正题:
首先,如何判断某些题目是不是状压$dp$呢,要看$n$的取值范围,当较小的时候,就可以考虑状压了。
那么我们设$f[j][i]$表示以第$j$头牛结尾,也就是最后一次加入队列的是第$j$头牛,并且现在队列状态为$i$的时候的方案数。
那么我们考虑现在要加入第$k$头奶牛,那么我们需要考虑一下几种情况:
$1、$第$j$头奶牛与新加的第$k$头奶牛相差不超过题目要求的时候,要排除
$2、$状态中第$j$头奶牛这个位置要为$1$,因为$j$既然是最后加入的,那肯定在队列中
$3、$状态中第$k$头奶牛这个位置要为$0$,因为你要加入他。
代码如下:
#include<iostream> #include<cstdio> #include<cmath> #define int long long #define N 20 using namespace std; int n,m; int val[N],f[N][1<<N]; signed main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i) scanf("%lld",&val[i]); for(int i=1;i<=n;++i) f[i][1<<(i-1)]=1; for(int i=1;i<(1<<n);++i) for(int j=1;j<=n;++j) for(int k=1;k<=n;++k) { if(((1<<(j-1))&i)==0||((1<<(k-1))&i)||abs(val[k]-val[j])<=m) continue; f[k][i+(1<<(k-1))]+=f[j][i]; } int ans=0; for(int i=1;i<=n;++i) ans+=f[i][(1<<n)-1]; printf("%lld",ans); return 0; }