zoukankan      html  css  js  c++  java
  • B君的第九题

    B君的第九题

    对于一个排列(a_1, a_2,dots,a_n),如果对于一个i满足(a_{i-1}<a_i>a_i+1)则称i是一个极大值。我们认为(a_0=a_{n+1}=0)。考虑(1,2,dots,n)的所有排列,问有多少个排列恰好有m个极大值。输出答案对p取模的结果。(1le nle10^9, 1le mle10, 2le ple1001)

    对于统计排列数,其实没有必要按照给出的a的顺序来dp,可以先把a从小到大排序,然后用(f[i][j])表示dp到第i个数,有j个山峰的方案数。由于当前数大于之前序列的所有数,考虑把它插入序列。如果它插在山峰旁边,那么山峰个数仍然不变,否则山峰个数会加一个。因此(f[i][j]=f[i-1][j]*2j+f[i-1][j-1]*(i-2*(j-1)))

    但是这个式子和i有关,没法用矩阵乘法优化dp。怎么办呢?由于所有运算都是在模p意义下的,所以说直接对于i=1到p先把矩阵暴力求出来,然后用矩阵快速幂即可!

    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int maxn=1e3+5, maxm=12;
    int n, m, p;
    inline void up(int &x, int y){ x+=y-p; x+=(x<0?p:0); }
    
    struct Matrix{
        int a[maxm][maxm];
    }g[maxn], re, c, ans;
    Matrix& operator *(const Matrix &a, const Matrix &b){
        memset(re.a, 0, sizeof(re.a));
        for (int i=0; i<=m; ++i)
            for (int j=0; j<=m; ++j)
                for (int k=0; k<=m; ++k)
                up(re.a[i][j], a.a[i][k]*b.a[k][j]%p);
        return re;
    }
    
    int main(){
        scanf("%d%d%d", &n, &m, &p);
        for (int i=0; i<=m; ++i) c.a[i][i]=1, ans.a[i][i]=1;
        for (int i=1; i<=p; ++i){
            for (int j=0; j<m; ++j){
            	//if (i-2*j<0) break;  //?
                g[i].a[j][j]=2*j%p,
                g[i].a[j][j+1]=((i-2*j)%p+p)%p;
            }
            g[i].a[m][m]=2*m%p;
            c=c*g[i];
        }
        int mi=n/p;
        for (; mi; c=c*c, mi>>=1) if (mi&1) ans=ans*c;
        for (int i=1; i<=n%p; ++i) ans=ans*g[i];
        printf("%d
    ", ans.a[0][m]);
        return 0;
    }
    
  • 相关阅读:
    CentOS linux系统搭建LAMP环境
    网站跳出率高的优化方案
    IT痴汉的工作现状24-Just for fun
    windows下远程连接ubantu
    Hibernate基础映射
    我院同学在2013年第四届“蓝桥杯”全国软件专业人才设计与创业大赛全国总决赛中获得佳绩
    Linux下打开串口设置
    zoj 3261 Connections in Galaxy War
    Android之startActivityForResult的使用
    当心Azure跨区域数据传输产生额外费用
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/9367818.html
Copyright © 2011-2022 走看看