zoukankan      html  css  js  c++  java
  • hdu 5852 :Intersection is not allowed! 行列式

    有K个棋子在一个大小为N×N的棋盘。一开始,它们都在棋盘的顶端,它们起始的位置是 (1,a1),(1,a2),...,(1,ak) ,它们的目的地是 (n,b1),(n,b2),...,(n,bk)。

    一个位于 (r,c) 的棋子每一步只能向右走到 (r,c+1) 或者向下走到 (r+1,c) 。

    我们把 i 棋子从 (1,ai) 走到 (n,bi) 的路径记作 pi 。

    你的任务是计算有多少种方案把n个棋子送到目的地,并且对于任意两个不同的棋子 i,j ,使得路径 pi 与 pj 不相交(即没有公共点)。

    容斥原理。

    假设只有两个点,那么答案就是它们以任意路径到达终点的方案数减去相交的方案。

    比如 a1->b1 ,a2->b2 ,那它们相交的方案就是 a1->b2,a2->b1的所有方案。

    因为在最后一个交点下把两条路径换一下它们是一一对应的。

    扩展到多个点时有$n!$种向下对应对应的方案,每个方案的容斥系数是$-1^{逆序对个数}$。

    实际上这东西就是矩阵的行列式。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define ll long long
     6 #define N 105
     7 using namespace std;
     8 int n,k;
     9 const int inf = 200000;
    10 const int p = 1000000007;
    11 int jie[200005],ni[200005];
    12 void yu()
    13 {
    14     jie[0]=ni[0]=ni[1]=1;
    15     for(int i=1;i<=inf;i++)jie[i]=1LL*i*jie[i-1]%p;
    16     for(int i=2;i<=inf;i++)ni[i]=(1LL*(-p/i)*ni[p%i]%p+p)%p;
    17     for(int i=1;i<=inf;i++)ni[i]=1LL*ni[i-1]*ni[i]%p;
    18 }
    19 int pw(ll x,int y)
    20 {
    21     ll lst=1;
    22     while(y)
    23     {
    24         if(y&1)lst=lst*x%p;
    25         y>>=1;
    26         x=1LL*x*x%p;
    27     }
    28     return (int)lst;
    29 }
    30 int c(int n,int m)
    31 {
    32     return 1LL*jie[n]*ni[m]%p*ni[n-m]%p;
    33 }
    34 int st[N],ed[N];
    35 ll a[N][N];
    36 void guess()
    37 {
    38     ll ans=1;
    39     for(int i=1;i<=k;i++)
    40     {
    41         for(int j=i;j<=k;j++)
    42         {
    43             if(a[j][i])
    44             {
    45                 if(j!=i)ans*=-1;
    46                 for(int l=1;l<=k;l++)swap(a[i][l],a[j][l]);
    47                 break;
    48             }
    49         }
    50         ll tp=pw(a[i][i],p-2);
    51         for(int j=i+1;j<=k;j++)
    52         {
    53             if(a[j][i])
    54             {
    55                 ll tmp=p-tp*a[j][i]%p;
    56                 for(int l=i;l<=k;l++)
    57                 {
    58                     a[j][l]=(a[j][l]+tmp*a[i][l]%p)%p;
    59                 }
    60             }
    61         }
    62     }
    63     if(ans==-1)ans=p-1;
    64     for(int i=1;i<=k;i++)ans=ans*a[i][i]%p;
    65     printf("%lld
    ",ans);
    66     return ;
    67 }
    68 int main()
    69 {
    70     yu();
    71     scanf("%d%d",&n,&k);
    72     for(int i=1;i<=k;i++)scanf("%d",&st[i]);
    73     for(int i=1;i<=k;i++)scanf("%d",&ed[i]);
    74     for(int i=1;i<=k;i++)
    75     {
    76         for(int j=1;j<=k;j++)
    77         {
    78             if(ed[j]>=st[i])a[i][j]=c(n-1+abs(ed[j]-st[i]),n-1);
    79         }
    80     }
    81     guess();
    82     return 0;
    83 }
  • 相关阅读:
    linux 常用命令-编辑模式
    关于react虚拟DOM的研究
    oracle 分页的sql语句
    react+webpack+wepack-dev-server的环境中ant design图标离线的方法
    oracle 语句之对数据库的表名就行模糊查询,对查询结果进行遍历,依次获取每个表名结果中的每个字段(存储过程)
    eclipse 中使用git
    好东西要分享
    《梦断代码》阅读笔记二
    《梦断代码》阅读笔记一
    第二段冲刺进程4
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6670187.html
Copyright © 2011-2022 走看看