2655: calc

来源:互联网 发布:梦想小镇淘宝充值 编辑:程序博客网 时间:2024/05/29 12:28

2655: calc

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 167  Solved: 108
[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

[Submit][Status][Discuss]

定义状态f[i][j]:1~i中的数选了j个组成序列,权值总和
那么,f[i][j] = f[i-1][j] + i * j * f[i-1][j-1],初值f[i][0] = 1,直接递推O(n * A)
不过,打表验证可知,f[i][n]是一个与i有关的2n次多项式,这是一个很棒的性质!
因此,求出f[2n][n]以内的所有值,随便上一个插值法就行了

如何看出2n次多项式???一个差分k + 1次后全部变成0的序列是一个最高次项为k的多项式
#include<iostream>#include<cstdio>#include<cstring>#include<map>using namespace std; typedef long long LL;const int maxn = 505; int Ans,A,n,f[maxn*2][maxn];LL p; map <int,int> Inv; int Mul(const LL &x,const LL &y) {return x * y % p;}int Add(const int &x,const int &y) {return (x + y) % p;}int Dec(const int &x,const int &y) {return (x - y + p) % p;} int ksm(int x,int y){    int ret = 1;    for (; y; y >>= 1)    {        if (y & 1) ret = Mul(ret,x);        x = Mul(x,x);    }    return ret;} int main(){    #ifdef DMC        freopen("DMC.txt","r",stdin);    #endif         cin >> A >> n >> p; f[0][0] = 1;    for (int i = 1; i <= 2 * n; f[i][0] = 1,i++)        for (int j = 1; j <= n; j++)            f[i][j] = Add(f[i-1][j],Mul(Mul(i,j),f[i-1][j-1]));    for (int i = 0; i <= 2 * n; i++)        for (int j = 0; j <= 2 * n; j++)            if (!Inv[i - j]) Inv[i - j] = ksm(Dec(i,j),p - 2);    for (int i = 0; i <= 2 * n; i++)    {        int B = 1;        for (int j = 0; j <= 2 * n; j++)            if (i != j) B = Mul(B,Mul(Dec(A,j),Inv[i - j]));        Ans = Add(Ans,Mul(B,f[i][n]));    }    cout << Ans << endl;    return 0;}

0 0