HDU 5226
题意:1e5*1e5的矩阵.当i<j时,a[i][j]=0; 当i>j时,a[i][j]=C(i,j).
现在给出(x1,y1),(x2,y2) 求子矩阵的和 x1,y1,x2,y2<=1e5.
求子矩阵和 尝试用二维前缀和来解决.则要知道(0,0)到(x,y)的和.
容易知道(0,x)行的第i列秩和 0+..0+C(i,i)+C(i+1,i)+...C(x,i) = C(x+1,i+1) (x+1件物品中取i+1件,最后一件为i+1,i+2,...x+1).
O(n)遍历列 前缀和减一减即可.
题意:1e5*1e5的矩阵.当i<j时,a[i][j]=0; 当i>j时,a[i][j]=C(i,j).
现在给出(x1,y1),(x2,y2) 求子矩阵的和 x1,y1,x2,y2<=1e5.
求子矩阵和 尝试用二维前缀和来解决.则要知道(0,0)到(x,y)的和.
容易知道(0,x)行的第i列秩和 0+..0+C(i,i)+C(i+1,i)+...C(x,i) = C(x+1,i+1) (x+1件物品中取i+1件,最后一件为i+1,i+2,...x+1).
O(n)遍历列 前缀和减一减即可.
p是素数可大可小,在套一下Lucas定理:C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll f[N],inv[N],x,y,x2,y2,p;
ll powmod(ll x,ll n)
{
ll s=1;
while(n)
{
if(n&1)
s=(s*x)%p;
x=(x*x)%p;
n>>=1;
}
return s;
}
void init()
{
f[0]=inv[0]=1;
for(int i=1;i<N;i++)
{
f[i]=(f[i-1]*i)%p;
inv[i]=powmod(f[i],p-2);
}
}
ll C(int n,int m)
{
if(n<m)
return 0;
return f[n]*inv[n-m]%p *inv[m] %p;
}
ll Lucas(int n,int m)
{
if(n<p&&m<p)
return C(n,m);
return Lucas(n/p,m/p)*Lucas(n%p,m%p)%p;
}
ll work(int x,int y)
{
ll res=0;
for(int i=0;i<=y;i++)
res=(res+Lucas(x+1,i+1))%p;
return res;
}
int main()
{
while(cin>>x>>y>>x2>>y2>>p)
{
init();
ll ans=0;
ans=(ans+work(x2,y2));
if(y)
ans=(ans-work(x2,y-1)+p)%p;
if(x)
ans=(ans-work(x-1,y2)+p)%p;
if(x&&y)
ans=(ans+work(x-1,y-1)+p)%p;
printf("%lld\n",ans);
}
return 0;
}