zoukankan      html  css  js  c++  java
  • STREAMING #5 题解 3.高位网络

    高维网络

    【题目描述】 
    现在有一个 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 取模的结果。 
    【输入样例】 
    2 1 
    2 1 
    1 0 
    【输出样例】 

    【数据范围】 
    这里写图片描述

     

    30分算法
    在前30分当中,数据规模非常小,可以暴搜每条路线。


    d=1的算法
    对于d=1的情况,如果没有点被破坏则答案是1,否则答案是0。 

    p=0的算法

    •运用排列组合公式:二维:C(n,n+m);

    多维:

    阶乘可以暴力算,注意除法要用逆元(费马小定理求逆元)算。

    【题解】【dp+组合数+容斥原理】 
    【f[i]表示从A到i不经过被破坏的点的路径条数;g[i][j]表示从i到j可以经过的被破坏的点的方案数(可以用组合数求)】 
    【g[i][j]:(各维度权值之和的阶乘)/(各维度阶乘之积),如二维情况:(行数+列数)!/(行数!×列数!)】 
    【f[i]=总路径条数-不合法,f[x]=g[A][x]-Σf[y]*g[y][x]】 
    【最后输出f[B]】

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<algorithm>
      5 #define man 10000010
      6 #define sc(x) scanf("%d",&x)
      7 #define ll long long
      8 #define mod 1000000007
      9 using namespace std;
     10 struct node
     11 {
     12     int x[110];
     13     }a[510];//每个点的坐标
     14 ll mi[man],sum[510],f[510],g[510][510],h[510];
     15 /*
     16     mi[]:求i的阶乘;
     17     sum[]:每个点的坐标和(为了之后的p=0做准备);
     18     f[]:从A到i不经过被破坏的点的路径条数;
     19     g[][]:从i到j可以经过的被破坏的点的方案数(可以用组合数求);
     20     h[]:每两个点坐标之间的差值;
     21     */
     22 int d,p;
     23 int cmp(node a,node b)
     24 {
     25     for(int i=1;i<=d;i++)
     26     {
     27         if(a.x[i]<b.x[i])return 1;
     28         if(a.x[i]>b.x[i])return 0;
     29         }
     30     }
     31 //    cmp:从一维开始从小到大排序;
     32 inline void pow1()
     33 {    mi[0]=1;
     34     for(ll i=1;i<=10000000;i++)
     35         mi[i]=(mi[i-1]*i)%mod;
     36     }
     37 //pow1:计算阶乘;
     38 ll bpow(int a,int b)
     39 {
     40     ll ans=1,base=a;
     41     while(b)
     42     {
     43         if(b&1) ans=ans*base%mod;
     44         base=base*base%mod;
     45         b>>=1;
     46         }
     47     return ans;
     48     }
     49 //快速幂;
     50 inline void solve()
     51 {
     52     for(int i=1;i<=p;i++)
     53     {
     54         ll t=mi[sum[i]];
     55         ll t1=1;
     56         for(int j=1;j<=d;j++)
     57             if(a[i].x[j])
     58                 t1=(t1*mi[a[i].x[j]])%mod;
     59         ll ans=bpow(t1,mod-2);
     60         g[0][i]=t*ans%mod;
     61         }//运用费马小定理计算从A点至各点的路径总数;
     62     for(int i=1;i<=p;i++)
     63         for(int j=1;j<=p;j++)
     64         {
     65             ll tot=0;bool b=1;
     66             for(int k=1;k<=d;k++)
     67             {
     68                 h[k]=a[j].x[k]-a[i].x[k];
     69                 tot+=h[k];
     70                 if(h[k]<0) //因为是单向边(从i至j),所以j-i的坐标差>=0;
     71                 {
     72                     b=0;
     73                     break;
     74                     }
     75                 }
     76                 if(!b) continue;
     77                 ll t=mi[tot];
     78                 ll t1=1;
     79                 for(int k=1;k<=d;k++)
     80                     if(h[k]) t1=(t1*mi[h[k]])%mod;
     81                 ll ans=bpow(t1,mod-2);
     82                 g[i][j]=t*ans%mod;
     83             }//运用费马小定理求两点之间路径总数;
     84     return ;            
     85     }
     86     
     87 int main()
     88 {    freopen("cube.in","r",stdin);
     89     freopen("cube.out","w",stdout);
     90     sc(d);sc(p);
     91     p++;
     92     for(int i=1;i<=d;i++)
     93         sc(a[p].x[i]);//每维极值相当于B点(终点)坐标;
     94     for(int i=1;i<=p-1;i++)
     95         for(int j=1;j<=d;j++)
     96             sc(a[i].x[j]);
     97     sort(a+1,a+1+p,cmp);
     98     for(int i=1;i<=p;i++)
     99         for(int j=1;j<=d;j++)
    100         {sum[i]+=a[i].x[j];sum[i]%=mod;}
    101     pow1();
    102     solve();//预处理g[i][j];
    103     for(int i=1;i<=p;i++)
    104     {
    105         f[i]=g[0][i]%mod;
    106         for(int j=1;j<i;j++)
    107             f[i]=(f[i]-f[j]*g[j][i])%mod;
    108         f[i]=(f[i]%mod+mod)%mod;
    109         }
    110     cout<<f[p]<<endl;
    111     return 0;
    112     }

    费马小定理:a/b mod p ==a* b^p-2 mod p;

    证明略。

    欢迎大家吐槽或评论,如要转载请注明地址,谢谢~(虽然不一定有人能看到。。。)
  • 相关阅读:
    8-15 globalCompositeOperation阶段练习二
    8-13 canvas专题-阶段练习二(下)
    8-12 canvas专题-阶段练习一(上)
    最长公共字串
    8-23 canvas专题
    8-2 canvas专题-线条样式
    7-81 js课程小结
    7-80 HTML5新增的JS选择器
    VS快捷键教程
    java.text.NumberFormat使用方法
  • 原文地址:https://www.cnblogs.com/Slager-Z/p/7449371.html
Copyright © 2011-2022 走看看