高维网络
【题目描述】
现在有一个 d 维的坐标网格,其中第 i 维坐标的范围是[0,a_i]。 在这个范围内建立一个有向图:我们把范围内的每个整点(每一维坐标均 为整数的点)当做图上的顶点。设点 A(0,0,⋯,0),B(a_1,a_2,⋯,a_d)。 对于范围内的点(x_1,x_2,⋯,x_d),它会向以下这些点(如果目标点在 范围内)连有向边: (x_1+1,x_2,⋯,x_d),(x_1,x_2+1,⋯,x_d),⋯,(x_1,x_2,⋯,x_d+1) 现在从点 A 到点 B 会有若干条路径,路径的条数可以十分简单地算出。然 而不幸的是,范围内有 p 个点被破坏了(点 A 和点 B 不会被破坏) ,其中第 i 个点的坐标为(x_(i,1),x_(i,2),⋯,x_(i,d))。你需要算出从点 A 到点
B 剩余的路径条数。 由于答案可能很大,你只需要输出它对 1,000,000,007 取模的结果。
【输入格式】
第一行为两个整数 d,p。
第二行为 d 个整数,其中第 i 个数是 a_i。
接下来 p 行,每行 d 个整数,其中第 i 行第 j 个数是 x_(i,j)。
【输出格式】
一个整数,表示从点 A 到点 B 剩余的路径条数对 1,000,000,007 取模的
结果。
【输入样例】
2 1
2 1
1 0
【输出样例】
1
测试点编号 ai ≤ d = p = 1 100,000 1 0 2 8 2 1 3 9 2 2 4 10 2 3 5 4 3 2 6 5 3 4 7 100,000 1 5 8 100 2 0 9 500 2 0 10 1,000 2 20 11 50 3 0 12 100 3 20 13 10,000 2 0 14 50,000 2 0 15 100,000 2 500 16 10,000 3 0 17 100,000 3 500 18 100,000 10 500 19 100,000 50 0 20 100,000 100 500
题解:dp
f[x]表示A到x且不经过被破坏的点的方案数
g[x][y]表示x到y可以经过被破坏的点的方案数
g可以用组合数算,以二维为例g[0][x]=(行数+列数)!/(行数!*列数!) ,0表示起点
f用总数减去不合法的,不合法的枚举第一个经过的被破坏的格子。
f[x]=g[A][x]-Σf[y]*g[y][x]
f[B]就是答案
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#define N 503
#define mod 1000000007
#define LL long long
using namespace std;
int d,p;
LL g[N][N],f[N],a[N],sum[N],jc[10000003];
LL h[N];
struct data
{
int x[N];
}point[N];
void calc()
{
jc[0]=1;
for (LL i=1;i<=10000000;i++)
jc[i]=(LL)(jc[i-1]*i)%mod;
}
LL inv(LL num,LL x)
{
LL base=num%mod; LL ans=1;
while(x)
{
if (x&1)
ans=ans*base%mod;
x>>=1;
base=base*base%mod;
}
return ans%mod;
}
void solve()
{
for (int i=1;i<=p;i++)
{
LL t=jc[sum[i]];
LL t1=1;
for (LL j=1;j<=d;j++)
if (point[i].x[j]) t1=(t1*jc[point[i].x[j]])%mod;
//cout<<t1<<endl;
LL poww=inv(t1,mod-2);
//cout<<poww<<endl;
g[0][i]=t*inv(t1,mod-2)%mod;
//cout<<"0 "<<" "<<i<<" "<<g[0][i]<<endl;
}
for (int i=1;i<=p;i++)
for (int j=1;j<=p;j++)
if (i!=j)
{
LL tot=0;
bool pd=true;
for (int k=1;k<=d;k++)
{
h[k]=point[j].x[k]-point[i].x[k],tot+=h[k];
if (h[k]<0) {
pd=false;
break;
}
}
if (!pd) continue;
LL t=jc[tot]; LL t1=1;
for (int k=1;k<=d;k++)
if (h[k]) t1=(t1*jc[h[k]])%mod;
//cout<<t1<<endl;
g[i][j]=t*inv(t1,mod-2)%mod;
//cout<<i<<" "<<j<<" "<<g[i][j]<<endl;
}
}
int cmp(data x,data y)
{
for (int i=1;i<=d;i++)
{
if (x.x[i]<y.x[i]) return 1;
if (x.x[i]>y.x[i]) return 0;
}
}
int main()
{
freopen("cube.in","r",stdin);
freopen("cube.out","w",stdout);
scanf("%d%d",&d,&p);
for (int i=1;i<=d;i++) scanf("%d",&a[i]);
for (int i=1;i<=p;i++)
{
for (int j=1;j<=d;j++)
scanf("%d",&point[i].x[j]);
}
p++;
for (int i=1;i<=d;i++)
point[p].x[i]=a[i];
sort(point+1,point+p+1,cmp);
for (int i=1;i<=p;i++)
{
for (int j=1;j<=d;j++)
sum[i]+=(LL)point[i].x[j];
}
calc();
solve();
for (int i=1;i<=p;i++)
{
f[i]=g[0][i]%mod;
for (int j=1;j<i;j++)
f[i]=(f[i]-f[j]*g[j][i])%mod;
f[i]=(f[i]%mod+mod)%mod;
}
printf("%I64d\n",f[p]);
}