题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6630
题意:给定n, x, y,问有多少个n的排列能满足相邻两个数字相差小于等于2
题解:考虑一个一个的填数字的话,因为1-n的每个数字都要用上,所以x必须往小先走到1在往大走,如果x不慢慢走到1的话,到后面1这个数字就没有办法填进去了,y同理(应该先往大走到n在往小走)。然后会发现前面(后面)一小段填数字的方法只有一种,以n = 12, x = 4, y = 9为例,这时候数字序列一定是这个样子:4, 2, 1, 3 ,5, ......, 8, 10, 12, 11, 9,这个时候就转换成求5, 6, 7, 8这几个数字的排列,相当于是1, 2, 3, 4。这时候问题就可以变成,求有多少个排列形如1, ......,n,且相邻数字之差小于等于2。考虑第n个数字,如果n前面的一个数字是n-1,则就是求1~n-1的排列数;如果n前面一个数字是n-2,那么n-2前面的一个数字只能是n-1,n-1前面的一个数字只能是n-3,则就是求1~n-3的排列数;故得到递推方程:f[i] = f[i-1] + f[i-3]。
写这个题的时候还要考虑给定的x,y会不会等于1,n。假设n = 12, x = 1, y = 9此时y往后填数字只有一种方法填到y+1,但是x是不用继续往后填数字的,所以答案是1~y+1的排列数。
代码:
#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
using namespace std;
const int maxn = 1e5+5;
ll dp[maxn];
void init(){
dp[1] = 1;
dp[2] = 1;
dp[3] = 1;
for(int i = 4; i < 1e5; i++){
dp[i] = (dp[i-1]%mod + dp[i-3]%mod)%mod;
}
}
int main(){
init();
int T;
cin >> T;
while(T--){
int n, x, y;
cin >> n >> x >> y;
if(x != 1) x++;
if(y != n) y--;
cout << dp[y-x+1] << endl;
}
}