[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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair pii;
typedef long double ld;
typedef unsigned long long ull;
typedef pair 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
}

转载于:https://www.cnblogs.com/wawawa8/p/11113776.html

你可能感兴趣的:([CQOI2018]交错序列)