zoukankan      html  css  js  c++  java
  • luogu P4463 [集训队互测2012] calc

    先考虑一个朴素的DP:设 (f_{i,j}) 表示第 (i) 个位置填 (1sim j) 的所有升序序列对答案的贡献。转移方程:

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

    这样时间复杂度是 (O(nk)) 的,无法接受。

    我们先假设 (f_{i}(j)=f_{i,j}) 是关于 (j) 的一个多项式,次数设为 (g(i))。我们发现状态转移方程中一个差分的形式:

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

    那么次数的方程:

    [g(i)-1=g(i-1)+1 ]

    所以得出:

    [g(i)=g(i-1)+2 ]

    显然 (g(0)=0),那么以上假设成立(严谨证明可使用数学归纳法):(f_i(j)) 是关于 (j)(2 imes i) 次多项式。所以我们只需要计算出 (f_{i,1}sim f_{i,2n+1}) 的值,然后拉格朗日插值即可。

    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define int long long
    
    using namespace std;
    
    const int N=1009;
    int k,n,p,f[N][N],pre[N],suf[N],fac[N],inv_fac[N];
    
    void init()
    {
    	scanf("%lld %lld %lld",&k,&n,&p);
    }
    
    int ksm(int a,int b)
    {
    	int res=1;
    	while(b)
    	{
    		if(b&1)
    			res=res*a%p;
    		b>>=1,a=a*a%p;
    	}
    	return res;
    }
    
    int calc(int x,int k)
    {
    	pre[0]=suf[k+2]=1;
    	for (int i=1;i<=k+1;i++)
    		pre[i]=pre[i-1]*(x-i)%p;
    	for (int i=k+1;i>=1;i--)
    		suf[i]=suf[i+1]*(x-i)%p;
    	fac[0]=1;
    	for (int i=1;i<=k+1;i++)
    		fac[i]=fac[i-1]*i%p;
    	inv_fac[k+1]=ksm(fac[k+1],p-2);
    	for (int i=k;i>=0;i--)
    		inv_fac[i]=inv_fac[i+1]*(i+1)%p;
    	int ans=0;
    	for (int i=1;i<=k+1;i++)
    		ans=(ans+f[n][i]*pre[i-1]%p*suf[i+1]%p*inv_fac[i-1]%p*inv_fac[k+1-i]%p*((k+1-i&1)?-1:1))%p;
    	return ans;
    }
    
    void work()
    {
    	if(k<=2*n+1)
    	{
    		for (int i=1;i<=k;i++)
    			f[1][i]=i+f[1][i-1];
    		for (int i=2;i<=n;i++)
    			for (int j=1;j<=k;j++)
    				f[i][j]=(f[i][j-1]+f[i-1][j-1]*j%p)%p;
    		int tmp=1;
    		for (int i=1;i<=n;i++)
    			tmp=tmp*i%p;
    		printf("%lld
    ",tmp*f[n][k]%p);
    	}
    	else
    	{
    		int K=2*n+1;
    		for (int i=1;i<=K;i++)
    			f[1][i]=i+f[1][i-1];
    		for (int i=2;i<=n;i++)
    			for (int j=1;j<=K;j++)
    				f[i][j]=(f[i][j-1]+f[i-1][j-1]*j%p)%p;
    		printf("%lld
    ",(calc(k,2*n)+p)%p*fac[n]%p);
    	}
    }
    
    signed main()
    {
    	init();
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    类加载器
    类加载器
    类加载器
    类加载器
    Java11新特性
    Java11新特性
    Spring Cloud Alibaba学习笔记(24)
    Java11新特性
    PyCharm Professional 2016.1 破解 激活
    pycharm最新激活码 2018 2.28 到期
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13524753.html
Copyright © 2011-2022 走看看