• BZOJ 2655: calc


    2655: calc

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 182  Solved: 119
    [Submit][Status][Discuss]

    Description


      一个序列a1,...,an是合法的,当且仅当:
      长度为给定的n。
      a1,...,an都是[1,A]中的整数。
      a1,...,an互不相等。
      一个序列的值定义为它里面所有数的乘积,即a1a2...an。
      求所有不同合法序列的值的和。
      两个序列不同当且仅当他们任意一位不一样。
      输出答案对一个数mod取余的结果。

    Input

      一行3个数,A,n,mod。意义为上面所说的。

    Output

      一行结果。

    Sample Input

    9 7 10007


    Sample Output

    3611

    HINT

    数据规模和约定

      0:A<=10,n<=10。

      1..3:A<=1000,n<=20.

      4..9:A<=10^9,n<=20

      10..19:A<=10^9,n<=500。

      全部:mod<=10^9,并且mod为素数,mod>A>n+1

    Source

    分析:

    首先我们可以得出一个时间空间复杂度都爆炸的dp方程,大概可以拿到20分的样子...

    首先我们将序列有序化,然后最后乘上$n!$...

    定义$f[i][j]$为用$[1,i]$里面的数字组成$a[1]~a[j]$的答案...

    那么$f[i][j]=f[i-1][j]+f[i-1][j-1]*i$...

    然后我就不会了...跑去膜拜题解...http://blog.csdn.net/ta201314/article/details/52753481

    发现有两种做法:拉格朗日插值法&容斥原理...

    首先是拉格朗日插值法...

    我们可以发现,所有的$f[i][j](i<j)$都是$0$,然后对于所有的$f[i][j](i>=j)$我们研究暴力转移的方程:$f[i][j]=i*sum _{k=1}^{i-1} f[k][j-1]$,发现这是一个$f[i][j]=i*s(i-1,j-1)$的形式,那么我们猜想$f[x][i]$是一个关于$x$的多项式,然后发现对于$f[x][i]$和$f[x][i-1]$,$f[x][i]$比$f[x][i-1]$的次数大二:一个是前缀和使得次数+1,另一个是乘了一个$x$又使得次数+1...所以其实$f[i][j]$就是一个最高项次数为$2j$的多项式,那么问题就是求出每一项的系数,用拉格朗日插值法来求...

    拉格朗日插值法就是$f(x)=sum _{i=0}^{n} a_{i}x^{i}=sum _{i=0}^{n} f(x _{i})prod _{j=0}^{n} frac {x-x _{j}}{x _{i}-x _{j}}[i≠j]$

    有了这个东西我们就可以在$O(2*n*n)$的时间复杂度内得出答案...

    代码:

    拉格朗日插值法:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
    
    const int maxn=1000+5,maxm=500+5;
    
    int n,m,cnt,mod;
    
    long long x[maxn],y[maxn],f[maxn+maxm][maxm],fac[maxn];
    
    long long power(long long x,int y){
    	long long ans=1;
    	while(y){
    		if(y&1)
    			(ans*=x)%=mod;
    		(x*=x)%=mod,y>>=1;
    	}
    	return ans;
    }
    
    signed main(void){
    	scanf("%d%d%d",&m,&n,&mod);
    	f[0][0]=1;fac[0]=1;cnt=0;
    	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
    	for(int i=1;i<=n*3+5;i++)
    		for(int j=0;j<=n;j++){
    			if(j)
    				f[i][j]=(f[i-1][j]+f[i-1][j-1]*i%mod)%mod;
    			else
    				f[i][j]=f[i-1][j];
    		}
    	if(n*3+5>=m){
    		printf("%lld
    ",f[m][n]*fac[n]%mod);
    		return 0;
    	}
    	for(int i=1;cnt<=(n<<1)+1;i++)
    		if(f[i][n]&&i!=m)
    			x[++cnt]=i,y[cnt]=f[i][n];
    	long long a=1,b,ans=0;
    	for(int i=1;i<=cnt;i++)
    		(a*=(m-x[i]+mod)%mod)%=mod;
    	for(int i=1;i<=cnt;i++){
    		b=(m-x[i]+mod)%mod;
    		for(int j=1;j<=cnt;j++)
    			if(i!=j)
    				(b*=(x[i]-x[j]+mod)%mod)%=mod;
    		(ans+=a*power(b,mod-2)%mod*y[i]%mod)%=mod;
    	}
    	printf("%lld
    ",ans*fac[n]%mod);
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    Springboot学习:核心配置文件
    Springboot学习:底层依赖与自动配置的原理
    Springboot学习:介绍与HelloWorld
    js根据时间戳倒计时
    windows phone 豆瓣api的封装
    Android开发初始
    PHP(一)
    程序员修炼之道(一)
    WebClient和HttpReuqest两种网络请求的方式
    黑客与画家(二)
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6421665.html
Copyright © 2020-2023  润新知