洛谷 P2915 [USACO08NOV]奶牛混合起来Mixed Up Cows 解题报告
P2915 [USACO08NOV]奶牛混合起来Mixed Up Cows
题意:
给定一个长\(N\)的序列,求满足任意两个相邻元素之间的绝对值之差不超过\(K\)的这个序列的排列有多少个?
范围:
\(0<=n<=16,0<=序列元素<=25000,0<=k<=3400\)
统计次数一般是递推干的事情,但是我们发现,这个递推并没有一个很明显的顺序关系,并不可以说前几个转移到下一个之类的。
看看数据这么小,一般都是状压干的事情了。
我们可以按照规模进行递推,即一个大小为多少的子序列往后推。层次关系为小的子序列推大的子序列。
\(dp[i][j]\)代表子序列状态为\(i\),最后一个元素为原数列的第\(j\)号元素时的方案数。
则状态转移:
\(dp[i][j]=\sum dp[k][l]\),右边是可能的合法转移。
因为直接枚举子集会有很多无用状态,所以我们采用记忆化搜索来找到合法转移。
Code:
#include <cstdio>
#include <cstring>
#define ll long long
ll dp[1<<16][17],s[17],n,k;
ll abs(ll x){return x>0?x:-x;}
void init()
{
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++)
scanf("%lld",s+i);
memset(dp,-1,sizeof(dp));
for(int i=1;i<=n;i++)
dp[1<<n-i][i]=1;
}
ll dfs(ll sta,ll las)
{
if(~dp[sta][las])
return dp[sta][las];
dp[sta][las]=0;
for(ll i=1;i<=n;i++)
if(i!=las&&(sta>>n-i)&1&&abs(s[las]-s[i])>k)
dp[sta][las]+=dfs(sta&(~(1<<n-las)),i);
return dp[sta][las];
}
int main()
{
init();
ll ans=0;
for(int i=1;i<=n;i++)
ans+=dfs((1<<n)-1,i);
printf("%lld\n",ans);
return 0;
}
2018.7.6