传送门https://www.lydsy.com/JudgeOnline/problem.php?id=4321
题意:给你有n个数从1~n,问有多少种方法可以组成一个序列,使得连续的数不相邻
题解:假设这n个数是从小到大一个一个加入数列中的,那么第n个人只有与第n-1个人在一起才是不合法的,所有我们定义dp状态为dp[i][j][0/1]表示前i个人,相邻的不合法的对数是j,并且第i个人是否与第i-1个人是否相邻的方案数
代码如下:
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define bug printf("********* ") #define FIN freopen("input.txt","r",stdin); #define FON freopen("output.txt","w+",stdout); #define IO ios::sync_with_stdio(false),cin.tie(0) #define debug1(x) cout<<"["<<#x<<" "<<(x)<<"] " #define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"] " #define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"] " LL read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-')f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } const double eps = 1e-8; const int mod = 7777777; const int maxn = 2e3 + 5; const int INF = 0x3f3f3f3f; const LL INFLL = 0x3f3f3f3f3f3f3f3f; LL dp[maxn][maxn][2]; int main() { /* 我们将n个数从小到大一个一个加入队列中,那么第n个人只有与第n-1个人在一起才是不合法的, 所以我们记录f[i][j][0/1]表示前i个人,相邻的不合法的对数是j, 第i个人和第i-1个人是否相邻 的方案数。那么转移方程也很容易得出。*/ int n; while(~scanf("%d", &n)) { dp[2][1][1] = 2; for(int i = 3; i <= n; i++) { for(int j = 0; j < i; j++) { dp[i][j][0] = ((i - j - 2) * dp[i - 1][j][0] + (j + 1) * dp[i - 1][j + 1][0] + (i - j - 1) * dp[i - 1][j][1] + (j) * dp[i - 1][j + 1][1]) % mod; if(j) dp[i][j][1] = (2 * dp[i - 1][j - 1][0] + dp[i - 1][j][1] + dp[i - 1][j - 1][1]) % mod; } } printf("%lld ", dp[n][0][0]); } return 0; }