【问题描述】
现在有一个?维的坐标网格,其中第?维坐标的范围是[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; }