HDU6630 permutation 2

题意

给你一个数字 n (2<=n<=1e5),代表长度为 n 的排列(第 i 个数字为 p i p_{i} pi ),并且给你两张正整数 x, y,问满足下面条件的排列有多少种:

  • p 1 = x p_{1}=x p1=x
  • p n = y p_{n}=y pn=y
  • 对于所有的 1 &lt; = i &lt; n 1&lt;=i&lt;n 1<=i<n ∣ p i − p i + 1 ∣ &lt; = 2 | p_{i}-p_{i+1}|&lt;=2 pipi+1<=2

真题解:

在这里插入图片描述

假题解:

首先分析一个很经典的问题,当 x = 1 , y = n x=1,y=n x=1,y=n有多少种排列
通过打表很容易得到递推式, dp(n) = dp(n-1) + dp(n-3);
但是分析也是很重要的,
考虑长度为 n 的排列,最后一位是 n, 则倒数第二位只能是 n-1 或者 n-2
p n − 1 = n − 1 p_{n-1}=n-1 pn1=n1的时候 ,dp(n) = dp(n-1)
p n − 1 = n − 2 p_{n-1}=n-2 pn1=n2的时候 ,则倒数第三位只能放 n-1 ,因为如果 n-1 只能放在 n-2 和 n-3 之间,这时候不放 n-1 ,后面依次放下去一定不合法, 因为已经放了  n-1,n-2,n ,倒数第四位一定是 n-3,原因上面已经说明,则 dp(n) = dp(n-3)
两种策略合起来,则

d p ( n ) = d p ( n − 1 ) + d p ( n − 3 ) dp(n)=dp(n-1)+dp(n-3) dp(n)=dp(n1)+dp(n3)

但是这个题目如何分析呢,因为首位是 x,末尾是 y,不妨设x<y并且 x!=1 , y!=n(请注意)
因为第一位为 x,我第二位能放 x-2,x-1,x+1,x+2 ,有这四种情况
分析:

  • p 2 = x + 1 p_{2}=x+1 p2=x+1,则 p 3 p_{3} p3 一定要为 x-1 ,不然比 x 小的没法放了,现在已经有了  x , x + 1 , x − 1 x,x+1,x-1 x,x+1,x1,仔细分析发现只能减少了,不能再增加了,所以这种策略失败

  • p 2 = x + 2 p_{2}=x+2 p2=x+2,如果一直增加,肯定只会增加2(增加1上面证明了是失败了策略),然后再来分析能不能减少,考虑最简单的只有 p 1 , p 2 p_{1},p_{2} p1,p2也就是 x,x+2, 减少只能放 x+1, 然后现在要么减少要么增加,肯定不能又把 1放好又把 y 放好,则这种策略也失败了

  • p 2 = x − 1 p_{2}=x-1 p2=x1,和第一种方案类似,不能全部放完,失败。

  • p 2 = x − 2 p_{2}=x-2 p2=x2,由于前面几次的分析,发现必须得把1放好,也就是一直放到最小,切每次减2,相当于 x,x-2,x-4,…,1(偶数的话直接2在1), 然后在看x的是奇数偶数,,举个例子

  • x = 5 , 5 − &gt; 3 − &gt; 1 − &gt; 2 − &gt; 4 − &gt; 6 x=5,5-&gt;3-&gt;1-&gt;2-&gt;4-&gt;6 x=55>3>1>2>4>6

  • x = 6 , 6 − &gt; 4 − &gt; 2 − &gt; 1 − &gt; 3 − &gt; 7 x=6,6-&gt;4-&gt;2-&gt;1-&gt;3-&gt;7 x=66>4>2>1>3>7

对于y同理,然后发现排列可以看做 首位是 x+1, 末位是 y-1 ,其他数为  [ x + 2 , y − 2 ] [x+2,y-2] [x+2,y2],同时减去x的话,不是我们上面那个dp 的结论吗

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#define LL long long
using namespace std;
const int INF=1e9;
const int N=1e5+5;
const int mod=998244353;
int dp[N];
int main()
{
    dp[1]=1;dp[2]=1;dp[3]=1;
    for(int i=4;i<N;i++)
        dp[i]=(dp[i-1]+dp[i-3])%mod;

    int t;cin>>t;
    while(t--){
        int n,x,y;
        scanf("%d%d%d",&n,&x,&y);
        if(x!=1)x=x+1;
        if(y!=n)y=y-1;
        printf("%d\n",dp[y-x+1]);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值