高维网络 (dp+组合数)

高维网络
【题目描述】
现在有一个 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]);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值