洛谷 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

posted @ 2018-07-06 16:36  露迭月  阅读(200)  评论(0编辑  收藏  举报