高维网络(dp+容斥?)
以下内容来自ShallWe's Blog
题目
高维网络
现在有一个\(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 取模的结果。
解题报告
好简单的题,没什么好说的。
因为坏点的个数很少,并且维数也不大,完全可以承受\(O(p^2*d)\)的复杂度。
突破点:统计\(f[i]\)表示从\(A\)点到\(i\)点,不经过其他坏点的方案数 ,很显然的一点是,总方案数-每个点作为第一个坏点的方案数为答案。
这就很容易了,只需要一个C(x,y)的函数:
inline int C(int x,int y){
long long tmp=1;
int sum=0;
for (int i=1;i<=d;i++){
tmp=che(tmp,inv[bad[y].x[i]-bad[x].x[i]]);
sum+=bad[y].x[i]-bad[x].x[i];
}
tmp=che(tmp,mul[sum]);
return (int)tmp;
}
这是统计方案数的函数,意思大概是将所有步求全排列再除去同种步的阶乘,简单易懂
然后 \(f[i]=C(A,i)-f[j](j \to i)\).简单易懂。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=501;
const int D=101;
const int M=1000000007;
struct badpoint{
int x[D];
} bad[N+1];
struct E{
int next,to;
E(int next=0,int to=0)
:next(next),to(to){}
} e[N*N];
int mul[10000001],inv[10000001];
int f[N],d,n,a[N],head[N],tot;
inline int che(int x,int y){
long long a=x,b=y,c=a*b%M;
return (int)c;
}
inline void cha(int &x,int y){
x=(x-y+M)%M;
}
inline int qpow(int x,int k){
long long ans=1,tmp=x;
for (int i=k;i;i>>=1){
if (i&1) ans=ans*tmp%M;
tmp=tmp*tmp%M;
}
return (int)ans;
}
void init(){
mul[0] = 1;
for (int i=1;i<=10000000;i++)
mul[i]=che(mul[i-1],i);
inv[10000000]=qpow(mul[10000000],M-2);
for (int i=10000000-1;i>0;i--)
inv[i]=che(inv[i+1],i+1);
inv[0]=1;
}
inline void in(int &x){
char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar());
for (x=0;ch>='0'&&ch<='9';ch=getchar())
x=x*10+ch-48;
}
inline void add(int x,int y){
e[++tot]=E(head[x],y);
head[x]=tot;
}
inline bool judge(int x,int y){
for (int i=1;i<=d;i++)
if (bad[x].x[i]>bad[y].x[i])
return 0;
return 1;
}
inline int C(int x,int y){
long long tmp=1;
int sum=0;
for (int i=1;i<=d;i++){
tmp=che(tmp,inv[bad[y].x[i]-bad[x].x[i]]);
sum+=bad[y].x[i]-bad[x].x[i];
}
tmp=che(tmp,mul[sum]);
return (int)tmp;
}
inline int dp(int x){
if (f[x]!=-1) return f[x];
f[x]=C(0,x);
int y;
for (int i=head[x];i;i=e[i].next){
y=e[i].to;
cha(f[x],che(dp(y),C(y,x)));
}
return f[x];
}
int main(){
freopen("cube.in","r",stdin);
freopen("cube.out","w",stdout);
init();
in(d),in(n);
for (int i=1;i<=d;i++)
in(a[i]),bad[n+1].x[i]=a[i];
for (int i=1;i<=n;i++)
for (int j=1;j<=d;j++)
in(bad[i].x[j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j&&judge(i,j))
add(j,i);
int y;
memset(f,-1,sizeof(f));
for (int i=1;i<=n;i++)
dp(i);
int ans=C(0,n+1);
for (int i=1;i<=n;i++)
cha(ans,che(f[i],C(i,n+1)));
printf("%d\n",ans);
return 0;
}