【NOIp模拟赛】高维网络
【问题描述】
现在有一个𝑑维的坐标网格,其中第𝑖维坐标的范围是[0, 𝑎𝑖]。
在这个范围内建立一个有向图:我们把范围内的每个整点(每一维坐标均为整数的点)当做图上的顶点。设点𝐴(0,0, ⋯ ,0), 𝐵(𝑎1, 𝑎2, ⋯ , 𝑎𝑑)。
对于范围内的点(𝑥1, 𝑥2, ⋯ , 𝑥𝑑),它会向以下这些点(如果目标点在范围内):
(𝑥1 + 1, 𝑥2, ⋯ , 𝑥𝑑), (𝑥1, 𝑥2 + 1, ⋯ , 𝑥𝑑), ⋯ , (𝑥1, 𝑥2, ⋯ , 𝑥𝑑 + 1)连有向边。
现在从点𝐴到点𝐵会有若干条路径,路径的条数可以十分简单地算出。然而不幸的是,范围内有𝑝个点被破坏了(点𝐴和点𝐵不会被破坏),其中第𝑖个点的坐标为(𝑥𝑖,1, 𝑥𝑖,2, ⋯ , 𝑥𝑖,𝑑)。你需要算出从点𝐴到点𝐵剩余的路径条数。
由于答案可能很大,你只需要输出它对1,000,000,007取模的结果。
【输入文件】
第一行为两个整数𝑑 𝑝。
第二行为𝑑个整数,其中第𝑖个数是𝑎𝑖。
接下来𝑝行,每行𝑑个整数,其中第𝑖行第𝑗个数是𝑥𝑖,𝑗。
【输出文件】
一个整数,表示从点𝐴到点𝐵剩余的路径条数对1,000,000,007取模的结果。
【输入样例】
2 1
2 1
1 0
【输出样例】
1
【样例解释】
如图所示,当删掉点(1,0)后,从点𝐴到点𝐵的 3 条路径只剩下了 1 条。
【数据规模和约定】
分析
题解原话(略有改动)
30分,暴力搜索每条路线
对于d=1的情况,如果没有点被破坏则答案是1,否则答案是0;
60分,动态规划
对于p=0的情况
如果看不懂上面的公式的话,可以举一个二维的例子
如果是二维的话,就相当于有一个n*m的方格,每次只能向右或向上走,有的点不能走,求从(0,0,)点到(n,m)点的路径数。这个显然要走n+m步,肯定有n步是向右的,那就是说在n+m步中选n步向右走所以就是C(n,n+m)
就是
当然C(m,n+m)和C(n,n+m)是一样的。意义的话类推一下就行了。
上述算法结合起来是可以得到80分的。
80分算法2
100分
还有要注意的一点是要防止中间过程运算的溢出。
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int mod=1000000007; const int maxn=100+5; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int d,p; int a[maxn],fac[10000005],sum[maxn*5]; int g[maxn*5][maxn*5],c[maxn],f[maxn*5];//g[i][j]表示i到j的路径数 struct node { int x[maxn]; }b[maxn*5];//那些不能通过的点要用结构体保存好排序。当然你如果要是用递归写的可能不用要。 bool cmp(node a,node b) { for(int i=1;i<=d;i++) { if(a.x[i]<b.x[i]) return 1; if(a.x[i]>b.x[i]) return 0; } } inline int power(int a,int n) { int res=1,base=a; while(n) { if(n&1) res=(ll)res*(ll)base%(ll)mod; base=(ll)base*(ll)base%(ll)mod; n=n>>1; } return res; } int inv(int x) {return power(x,mod-2);} void fct() { fac[0]=1; for(int i=1;i<=10000000;i++) fac[i]=(ll)fac[i-1]*(ll)i%(ll)mod; } void prework() { for(int i=1;i<=p;i++) { int t1,t2=1; t1=fac[sum[i]]; for(int j=1;j<=d;j++) if(b[i].x[j]) t2=(ll)t2*(ll)fac[b[i].x[j]]%(ll)mod; g[0][i]=(ll)t1*(ll)inv(t2)%(ll)mod; } for(int i=1;i<=p;i++) for(int j=1;j<=p;j++) if(i!=j) { bool flag=1; int s=0; for(int k=1;k<=d;k++) { c[k]=b[j].x[k]-b[i].x[k]; s+=c[k]; if(c[k]<0){ flag=0; break; } } if(!flag) continue; int t1,t2=1; t1=fac[s]; for(int k=1;k<=d;k++) if(c[k]) t2=(ll)t2*(ll)fac[c[k]]%(ll)mod; g[i][j]=(ll)t1*(ll)inv(t2)%(ll)mod; } } int main() { freopen("cube.in","r",stdin); freopen("cube.out","w",stdout); d=read(); p=read(); for(int i=1;i<=d;i++) a[i]=read(); for(int i=1;i<=p;i++) for(int j=1;j<=d;j++) b[i].x[j]=read(); p++; for(int i=1;i<=d;i++) b[p].x[i]=a[i]; sort(b+1,b+p+1,cmp); for(int i=1;i<=p;i++) for(int j=1;j<=d;j++) sum[i]+=b[i].x[j]; fct(); prework(); for(int i=1;i<=p;i++) { f[i]=g[0][i]; for(int j=1;j<i;j++) f[i]=((ll)f[i]-((ll)f[j]*(ll)g[j][i])%(ll)mod+mod)%mod; } printf("%d\n",f[p]); fclose(stdin); fclose(stdout); return 0; }