BZOJ4321 queue2 DP/递推

1 篇文章 0 订阅

BZOJ4321 queue2

Description

求1~n的序列,满足一个数的左右两边的差的绝对值不等与1的方案数。
对答案mod 7777777

题解

很奇怪的状态,看了题解才搞懂。
钦定f[i][j][1]表示推到第i个数,其中有j对数是相差1的,其中i,与i-1相邻
f[i][j][0]表示推到第i个数,其中有j对数是相差1的,其中i,与i-1不相邻。

我们先来分析i-1,i相邻,也就是f[i][j][1]怎么推。
对于i,i-1,i-2,有这几种关系,
本来i-1与i-2相邻,将i插入两者中,拆了一对(i-1,i-2),又形成了一对(i-1,i),这样方案来源于f[i-1][j][1]。
本来i-1与i-2相邻,将i插入与i-1相邻却不被i-1与i-2夹着,多形成了一对(i-1,i),这样方案来源于f[i-1][j-1][1]。
本来i-1与i-2不相邻,将i插入与i-1相邻,形成了一对(i-1,i),这样方案来源于f[i-1][j-1][1],由于i-1的左右够可以插,方案就乘2。
这样 f[i][j][1]=f[i1][j1][1]+f[i1][j][1]+f[i1][j1][0]2
关于i-1,i不相邻,也就是f[i][j][0]怎么推
本来i-1与i-2相邻,将i插入j对相邻的数的任意一对,这样就破坏了一对,这样方案来源于f[i-1][j+1][1],有(j+1-1)种位置可以选(i-1与i-2那对不能拆,因为插入又会形成新的)。
本来i-1与i-2不相邻,将i插入j对相邻的数的任意一对,这样就破坏了一对,这样方案来源于f[i-1][j+1][0],有(j+1)种位置可以选。
又可能i不去拆开相邻的数,就可以来源于
f[i-1][j][1]*(i-j-1)(可以插入i-1与i-2,不改变对数) 或 f[i-1][j][0]*(i-j-2)
综合

f[i][j][0]=f[i1][j+1][1]j+f[i1][j+1][0](j+1)+f[i1][j][1](ij1)+f[i1][j][0](ij2)

很难推的题呀。。。。

#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstring>
#define MAXN 1000+10
#define LL long long
#define MOD 7777777
using namespace std;
LL f[MAXN][MAXN][2],n;
int main()
{
    scanf("%lld",&n);
    f[1][0][0]=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
        {
            f[i][j][1]=(f[i-1][j][1]+f[i-1][j-1][1]+f[i-1][j-1][0]*2)%MOD;
            f[i][j][0]=(f[i-1][j+1][1]*j+f[i-1][j+1][0]*(j+1))%MOD;
            f[i][j][0]=(f[i][j][0]+f[i-1][j][1]*(i-j-1)+f[i-1][j][0]*(i-j-2))%MOD;
        }
    }
    printf("%lld\n",f[n][0][0]);
    return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值