数值微分(数学)(组合数)
看到题目我们有一个直观的想法,就是它的递推式很像组合数学中的杨辉三角。。。。
这样想的话很容易就能得出式子:
\[f[m](i)=\sum_{j=0}^{i}f(i-j)\times C_{m}^{j}\times (-1)^j
\]
举个例子:
\(f[4](3)\)
\(=f[3](3)-f[3](2)\)
\(=f[2](3)-2\times f[2](2)+f[2](1)\)
\(=f[1](3)-3\times f[1](2)+3\times f[1](1)-f[1](0)\)
因为\(f[1](0)\)是0,可以转换为\(f[0](0)\)
所以原式
\(=f[0](3)-4\times f[0](2)+6\times f[0](1)-4\times f[0](0)\)
那么接下来就是求组合数的问题了。
求组合数的方法有很多种,这里借鉴maomao9173 dalao的总结:
- 公式法 (这个复杂度很劣)
- 阶乘逆元求法 适用于多次查询,复杂度预处理O( n+logn ),查询接近O( 1 ),但是模数必须是质数。(100007不是质数)
(就是先O(n)预处理阶乘,然后算出来最大数的逆元,然后倒推回来。) - 杨辉三角递推求法 适用于多次密集小范围查询,复杂度预处理O( n^2 ),查询O( 1 )
(比如说NOIP2016day2t1) - 费马小定理/exgcd求逆元 单次O( logn ),是最简单的方法,模数必须为质数
- 阶乘分解 适用于模数不为质数的求法。复杂度预处理O( nlogn ),查询O( 1 )
而这个题就是用阶乘分解的方法来做。
\[C_m^j=\frac{m(m-1)...(m-j+1)}{j!}
\]
上下分别分解质因数,由于j!中的质因子都不超过n,所以只分解出2到n之间的质因子就可以了。
分解之后分子分母先对分解的因子进行约分,组合数是整数所以约分之后分母必定全部消去,剩下的分子只需要乘法计算。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1050;
const int Mod = 100007;
int n,m;
int dr[N];
int zuhe[N];
int xu[N][N],cxu[N][N],vxu[N];
int jia(int x,int y)
{
x+=y;
if(x>=Mod)
x-=Mod;
return x;
}
int jian(int x,int y)
{
x-=y;
if(x<0)
x+=Mod;
return x;
}
int cheng(int x,int y)
{
long long z=x;
z*=y;
z%=Mod;
x=z;
return x;
}
//dalao说把取模题中的加减乘操作都写成函数
//来替代常规的运算可以有效地避免取模出锅
int main()
{
//freopen("difer.in","r",stdin);
//freopen("difer.out","w",stdout);
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&dr[i]);
for(i=1;i<=n && i<=m;i++)
{
xu[i][0]=m+1-i;
for(j=2;j<=n;j++)
{
while(xu[i][0]%j==0)
{
xu[i][0]/=j;
xu[i][j]++;
}
}
//二维上面存储的是质因子为k,数组表示的是其对应的个数
xu[i][0]%=Mod;
}
//预先处理出[m,m-i+1]其中每个数的质因子(这些在分子上面)
for(i=1;i<=n && i<=m;i++)
{
cxu[i][0]=i;
for(j=2;j<=n;j++)
{
while(cxu[i][0]%j==0)
{
cxu[i][0]/=j;
cxu[i][j]++;
}
}
}
//预先处理出[1,i]其中每个数的质因子(这些在分母上)
//操作同上
zuhe[0]=1;
for(i=1;i<=n && i<=m;i++)
{
zuhe[i]=1;
for(j=1;j<=i;j++)
zuhe[i]=cheng(zuhe[i],xu[j][0]);
for(j=2;j<=n;j++)
vxu[j]+=xu[i][j]-cxu[i][j];
//分母分子相消
for(j=2;j<=n;j++)
{
for(k=1;k<=vxu[j];k++)
zuhe[i]=cheng(zuhe[i],j);
}
if(i&1)
zuhe[i]=jian(0,zuhe[i]);
}
for(i=1;i<=n;i++)
{
int res=0;
for(j=0;j<i && j<=m;j++)
res=jia(res,cheng(dr[i-j],zuhe[j]));
//最后把答案累计出来qwq
printf("%d\n",res);
}
return 0;
}