【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;
}
    
    
    

 

posted @ 2017-08-29 19:01  沐灵_hh  阅读(330)  评论(0编辑  收藏  举报