https://www.luogu.org/problemnew/show/P2915
在状态中加入上次所选的奶牛,f[i][S]表示上次选了i奶牛,此时选出奶牛集合为S的方案数。
转移用刷表更方便,枚举一个不在集合中的数k和在集合中的数j,由f[j][s]向f[k][s|(1<<j)]转移即可。
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int MAXN=17; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } long long f[MAXN][1<<MAXN]; int n,m,val[MAXN]; int main(){ n=rd();m=rd(); for(int i=1;i<=n;i++) val[i]=rd(); for(int i=1;i<=n;i++) f[i][1<<i-1]=1; for(int i=0;i<(1<<n);i++){ for(int j=1;j<=n;j++){ for(int k=1;k<=n;k++){ if(abs(val[j]-val[k])<=m) continue; if(!i&(1<<j-1)) continue; if(i&(1<<k-1)) continue; f[k][i|(1<<k-1)]+=f[j][i]; } } } long long ans=0; for(int i=1;i<=n;i++) ans+=f[i][(1<<n)-1]; cout<<ans; return 0; }