[CQOI2018]交错序列
[CQOI2018]交错序列
[题目链接]
[思路要点]
比较简单的 \(dp\) 题
状态比较好想,\(f[i][j]\) 表示当前填了前 \(i\) 个数字,第 \(i\) 个数字填了 \(0\) 的所有方案的 \(1\) 的个数的 \(j\) 次方和,\(g[i][j]\) 表示当前填了前 \(i\) 个数字,第 \(i\) 个数字填了 \(1\) 的所有方案的 \(1\) 的个数的 \(j\) 次方和
转移:
\[f[i][j]=f[i -1][j]+g[i-1][j] \\
g[i][j]=\sum_{k=0}^{j} C_{j}^{k}\cdot f[i-1][k]
\]
初值就是 \(f[1][0]=1,f[1][其它]=0,g[1][所有]=1\)
然后放到矩阵里做矩乘
[代码]
// Copyright: lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<long long,long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
#define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)
ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn = 110;
int n, a, b, mod;
int C[maxn][maxn];
int f[110], g[110];
inline int sum(int x, int y) {
return x + y >= mod ? x + y - mod : x + y;
}
inline int sub(int x, int y) {
return x - y < 0 ? x - y + mod : x - y;
}
inline int ksm(int x, int p) {
int ret = 1;
while (p) {
if (p & 1) ret = ret * 1ll * x % mod;
p >>= 1; x = x * 1ll * x % mod;
}
return ret;
}
int N;
struct Matrix {
int a[185][185];
Matrix (int x = 0) {
memset(a, 0, sizeof(a));
if (x == 1) rep(i, 0, 184) a[i][i] = 1;
}
inline Matrix operator * (const Matrix &b) const {
Matrix ret;
rep(i, 0, N) rep(j, 0, N) if (a[i][j] != 0) {
rep(k, 0, N) ret.a[i][k] = sum(ret.a[i][k], a[i][j] * 1ll * b.a[j][k] % mod);
}
// rep(i, 0, N) rep(j, 0, N) rep(k, 0, N) ret.a[i][j] = sum(ret.a[i][j], a[i][k] * 1ll * b.a[k][j] % mod);
return ret;
}
};
inline Matrix ksm(Matrix &x, int p) {
Matrix ret(1);
while (p) {
if (p & 1) ret = ret * x;
x = x * x; p >>= 1;
}
return ret;
}
void work() {
n = read(), a = read(), b = read(), mod = read();
C[0][0] = 1;
rep(i, 1, a + b) {
C[i][0] = 1;
rep(j, 1, i) C[i][j] = sum(C[i - 1][j], C[i - 1][j - 1]);
}
Matrix A;
A.a[0][0] = 1;
rep(i, 1, a + b) A.a[0][i] = 0;
rep(i, a + b + 1, a + b + a + b + 1) A.a[0][i] = 1;
N = a + b + a + b + 1;
Matrix B;
rep(j, 0, a + b) B.a[j][j] = 1, B.a[j + a + b + 1][j] = 1;
rep(j, 0, a + b) {
int nwj = a + b + 1 + j;
rep(k, 0, j) B.a[k][nwj] = C[j][k];
}
A = A * ksm(B, n - 1);
rep(i, 0, a + b) f[i] = A.a[0][i];
rep(i, 0, a + b) g[i] = A.a[0][a + b + 1 + i];
int ans = 0;
rep(i, 0, a) {
if ((a - i) & 1) ans = sub(ans, ksm(n, i) * 1ll * C[a][i] % mod * sum(f[a + b - i], g[a + b - i]) % mod);
else ans = sum(ans, ksm(n, i) * 1ll * C[a][i] % mod * sum(f[a + b - i], g[a + b - i]) % mod);
}
printf("%d\n", ans);
}
int main(){
#ifdef LZT
freopen("in","r",stdin);
#endif
work();
#ifdef LZT
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
}