Intersection is not allowed!

给出n∗n网格,顶部有k个起点,底部有k个相对应的终点
每次只能向下或向右走
求有多少种从各个起点出发到达对应终点且路径不相交的路径?(对109+7取模)



n*m空间从左上角走到右下角只走右或者下的方案数位C(n,n+m)

首先考虑两个棋子的情况,即一个棋子从a1到b1,另一个棋子从a2到b2,不考虑交叉方案数显然是C(b1-a1+n-1,n-1) * C(b2-a2+n-1,n-1)

对于路径交叉的方案,对于一个a1->b2,a2->b1的方案,这两条路径必然会相交,

把最后一个交叉点之后的两条路径交换就又对应一个a1->b1,a2->b2的路径交叉的方案

故我们建立了a1->b1,a2->b2交叉路径与a1->b2,a2->b1的方案的一一对应,那么不合法方案数就是C(b2-a1+n-1,n-1) * C(b1-a2+n-1,n-1)

多个棋子的情况,考虑容斥,如果两个路径相交,相当于交换了终点

枚举每个起点的终点,乘上一个容斥系数(−1)t,t表示相交的路径个数,(也可以看做选择的终点序列的逆序对个数)

按照每个起点选择每一个终点构造出一个组合数的矩阵,按照矩阵的的定义答案就是这个矩阵的行列式

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const ll mod=1000000007;
int inv[maxn],e[107],s[107],fac[maxn];
ll a[107][107];

ll det(int n) {
    ll ans=1;
    int k=0;
    for(int i=0;i<n;i++) {
        for(int j=i+1;j<n;j++) {
            int x=i,y=j;
            while(a[y][i]) {
                ll t=a[x][i]/a[y][i];
                for(int l=i;l<n;l++) a[x][l]=(a[x][l]-a[y][l]*t)%mod;
                swap(x,y);
            }
            if(x!=i) {
                for(int l=0;l<n;l++) swap(a[i][l],a[x][l]);
                k^=1;
            }
        }
        if(a[i][i]==0) return 0;
        else ans=ans*a[i][i]%mod;
    }
    if(k) ans=-ans;
    return (ans+mod)%mod;
}
void init() {
    inv[0]=inv[1]=1;
    fac[0]=fac[1]=1;
    for(int i=2;i<maxn;i++) {
        fac[i]=1ll*fac[i-1]*i%mod,
        inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
    }
    for(int i=2;i<maxn;i++) inv[i]=1ll*inv[i-1]*inv[i]%mod;
}
ll C(ll n,ll m) {
    if(m<0) return 0;
    return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main( ) {
    int t;
    cin>>t;
    init();
    while(t--) {
        int n,k;
        cin>>n>>k;
        for(int i=0;i<k;i++) cin>>s[i];
        for(int i=0;i<k;i++) cin>>e[i];
        for(int i=0;i<k;i++) {
            for(int j=0;j<k;j++) {
                a[i][j]=C(n-1+e[j]-s[i],e[j]-s[i]);
            }
        }
        cout<<det(k)<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wronin/p/11623714.html

时间: 2024-10-28 10:15:10

Intersection is not allowed!的相关文章

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 不相交(即没

Lindstr&#246;m–Gessel–Viennot lemma定理 行列式板子

https://blog.csdn.net/qq_37025443/article/details/86537261 博客 下面是wiki上的讲解,建议耐心地看一遍...虽然看了可能还是不懂 https://en.wikipedia.org/wiki/Lindström–Gessel–Viennot_lemma Lindström–Gessel–Viennot lemma定理是 起点集合A=(a1,a2,a3..an),终点集合B=(b1.b2,b3,..bn) 假定P是从一条从一个点到另一个点

[LeetCode] 349 Intersection of Two Arrays &amp; 350 Intersection of Two Arrays II

这两道题都是求两个数组之间的重复元素,因此把它们放在一起. 原题地址: 349 Intersection of Two Arrays :https://leetcode.com/problems/intersection-of-two-arrays/description/ 350 Intersection of Two Arrays II:https://leetcode.com/problems/intersection-of-two-arrays-ii/description/ 题目&解法

spark 教程三 spark Map filter flatMap union distinct intersection操作

RDD的创建 spark 所有的操作都围绕着弹性分布式数据集(RDD)进行,这是一个有容错机制的并可以被并行操作的元素集合,具有只读.分区.容错.高效.无需物化.可以缓存.RDD依赖等特征 RDD的创建基础RDD 1.并行集合(Parallelized Collections):接收一个已经存在的Scala集合,然后进行各种并行运算 var sc=new SparkContext(conf) var rdd=sc.parallelize(Array(2,4,9,3,5,7,8,1,6)); rd

350.求两个数组的交集 Intersection of Two Arrays II

Given two arrays, write a function to compute their intersection. Example:Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2]. Note: Each element in the result should appear as many times as it shows in both arrays. The result can be in any ord

【Leetcode】Insert Delete GetRandom O(1) - Duplicates allowed

题目链接:https://leetcode.com/problems/insert-delete-getrandom-o1-duplicates-allowed/ 题目: Design a data structure that supports all following operations in average O(1) time. Note: Duplicate elements are allowed. insert(val): Inserts an item val to the c

Intersection of Two Arrays I &amp; II

题目链接:https://leetcode.com/problems/intersection-of-two-arrays/ 题目大意:要求两个数组的交集(注意集合是不能含有重复的元素的) 方法1) 先对两个数组进行排序,设置两个指针pA和pB,分别指向这两个数组,比较nums1[pA]和nums[pB] a. 如果想等,则为交集中的元素,++pA, ++pB b. 如果nums[pA] < nums[pB],则++pA c. 否则,++pB 注意数组中有重复的元素(实现代码中的小trick)

Intersection of Two Linked Lists

Write a program to find the node at which the intersection of two singly linked lists begins. For example, the following two linked lists: A: a1 → a2 c1 → c2 → c3 B: b1 → b2 → b3 begin to intersect at node c1. Notes: If the two linked lists have no i

哈希(4) - 求两个链表的交集(intersection)以及并集(union)

给定两个链表,求它们的交集以及并集.用于输出的list中的元素顺序可不予考虑. 例子: 输入下面两个链表: list1: 10->15->4->20 list2: 8->4->2->10 输出链表: 交集list: 4->10 并集list: 2->8->20->4->15->10 方法1 (简单方法) 可以参考链表系列中的"链表操作 - 求两个链表的交集(intersection)以及并集(union)" 方法2