高维网络(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; 
}
posted @ 2016-08-11 20:24  ShallWe2000  阅读(213)  评论(0编辑  收藏  举报
Return Top
Dreams writes for dreamers like me.