zoukankan      html  css  js  c++  java
  • [国家集训队] calc

    题目

    显然有一个暴力(dp)

    (dp_{i,j})表示前(i)个数选了(j)个的答案

    转移显然

    [dp_{i,j}=dp_{i-1,j}+dp_{i-1,j-1} imes i ]

    由于元素是有顺序的,答案是(dp_{A,n} imes n!)

    复杂度是(O(nA))的显然过不了

    我们观察一下转移,简单一个移项

    [dp_{i,j}-dp_{i-1,j}=dp_{i-1,j-1} imes i ]

    我们如果把(dp_{i,j})视为一个与(i)有关的多项式,那么(dp_{i,j}-dp_{i-1,j})就是做了一个差分,发现得到的还是一个多项式,而且是一个次数比(dp_{j-1})高一次的多项式

    很显然(dp_{j})就比(dp_{j-1})高了两次,(dp_{0})是一个(0)次多项式,由此可以(dp_{j})是一个(2j)次多项式

    于是对于(dp_{A,n})就是一个(2n)次多项式,我们暴力dp出(2n)个取值之后大力拉格朗日插值就好了

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    const int maxn=1005;
    int dp[maxn][505],n,m,mod;
    inline int ksm(int a,int b) {
    	int S=1;
    	for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) S=1ll*S*a%mod;
    	return S;
    }
    int main() {
    	scanf("%d%d%d",&m,&n,&mod);dp[0][0]=1;
    	for(re int i=1;i<=2*n+1;i++) {
    		dp[i][0]=dp[i-1][0];
    		for(re int j=1;j<=i;j++) 
    			dp[i][j]=(dp[i-1][j]+1ll*dp[i-1][j-1]*i%mod)%mod;
    	}
    	int ans=0;
    	for(re int i=1;i<=2*n+1;i++) {
    		int q=1,p=1;
    		for(re int j=1;j<=2*n+1;j++)
    		if(i!=j) p=1ll*(m-j)*p%mod,q=1ll*(i-j)*q%mod;
    		q=(q+mod)%mod,p=(p+mod)%mod;
    		ans=(ans+1ll*dp[i][n]*p%mod*ksm(q,mod-2)%mod)%mod;
    	}
    	for(re int i=1;i<=n;i++) ans=1ll*ans*i%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    UVALive 6584 Escape (Regionals 2013 >> Europe
    莫比乌斯反演
    POJ 3986 Math teacher's homework
    ACM一些题目
    重探 DFT
    GDSOI2015 task4 ACU
    GDSOI2015 task2 覆盖半径
    USACO 2005 January Gold The Wedding Juicer
    CQOI2015 选数
    计算圆的包含(两两圆不相交)
  • 原文地址:https://www.cnblogs.com/asuldb/p/10927134.html
Copyright © 2011-2022 走看看