GLV HDU6482 HDU5852
GLV的maxn开两倍,防止溢出。
HDU6482
题意:给你x1,x2,y1,y2 (x1<x2,y1<y2),问你从(0,y1)->(x1,0),(0,y2)->(0,x2),只能往右、往下走的时候的路径不相交的条数是多少。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int mod=(int)1e9+7; 5 const int maxn=200005; 6 ll fac[maxn+5],inv_fac[maxn+5]; 7 8 ll quick(ll a,ll b){ 9 ll ans=1; 10 while(b){ 11 if(b&1) ans=ans*a%mod; 12 a=a*a%mod; 13 b/=2; 14 } 15 return ans; 16 } 17 void init(){ 18 inv_fac[0]=fac[0]=1,fac[1]=inv_fac[1]=1; 19 for(int i=2;i<maxn;i++) 20 fac[i]=fac[i-1]*i%mod; 21 inv_fac[maxn-1]=quick(fac[maxn-1],mod-2); 22 for(int i=maxn-2;i>=0;i--) 23 inv_fac[i]=inv_fac[i+1]*(i+1)%mod; 24 } 25 26 ll C(ll n,ll m){ 27 if(n<0||m<0||m>n) return 0; 28 if(n==m||m==0) return 1; 29 return fac[n]*inv_fac[n-m]%mod*inv_fac[m]%mod; 30 } 31 ll x[2],y[2]; 32 int main(){ 33 init(); 34 int t; 35 cin>>t; 36 while(t--){ 37 scanf("%lld%lld%lld%lld",&x[0],&x[1],&y[0],&y[1]); 38 ll ans1=C(x[1]+y[1],y[1]),ans2=C(x[0]+y[1],y[1]); 39 ll ans3=C(y[0]+x[1],y[0]),ans4=C(x[0]+y[0],y[0]); 40 printf("%lld\n",((ans1*ans4-ans2*ans3)%mod+mod)%mod); 41 42 } 43 return 0; 44 }
HDU5852
题意:给你一个n*n的矩阵,再第一行一次有k个起点1<=a1<a2<a3<...<ak<=n;最后一行有n个终点1<=b1<b2<b3<...<bk<=n;你只能向右或向下走,问你有多少种路线方案,使得ai->bi i=1...n;答案mod 1e9+7
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 typedef long long int ll; 7 8 const int MAXN = 2e5 + 10; 9 ll jc[MAXN]; 10 ll inv[MAXN]; 11 12 13 14 const ll MOD = 1e9 + 7; 15 const int N = 1e2 + 10; 16 ll a[N][N]; 17 18 ll pow(ll a, ll n, ll p) //快速幂 a^n % p 19 { 20 ll ans = 1; 21 while (n) { 22 if (n & 1) ans = ans * a % p; 23 a = a * a % p; 24 n >>= 1; 25 } 26 return ans; 27 } 28 29 ll niYuan(ll a, ll b) //费马小定理求逆元 30 { 31 return pow(a, b - 2, MOD); 32 } 33 34 35 inline ll C(int a, int b) //计算C(a, b),a下,b上 36 { 37 if (b > a) return 0; 38 return jc[a] * inv[b] % MOD 39 * inv[a - b] % MOD; 40 } 41 42 void init() 43 { 44 ll p = 1; 45 jc[0] = 1; 46 jc[1] = 1; 47 inv[0] = 1; 48 inv[1] = 1; 49 for (int i = 2;i < MAXN;i++) { 50 p = (p * i) % MOD; 51 jc[i] = p; 52 //inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD; 53 } 54 55 for (int i = 2;i < MAXN;i++) inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD; //O(n)求逆元 56 for (int i = 2;i < MAXN;i++) inv[i] = inv[i - 1] * inv[i] % MOD; //扩展到i!的逆元 57 } 58 59 60 ll determinant(int n) 61 { 62 //a为方阵 63 //MOD根据实际情况而定 64 ll ans = 1; 65 for (int k = 1;k <= n;k++) //将a[k+1..n][k]都变成0 66 { 67 ll pos = -1; 68 for (int i = k;i <= n;i++) //找到a[k..n][k]中第一个非0元素 69 if (a[i][k]) 70 { 71 pos = i; 72 break; 73 } 74 if (pos == -1)return 0; //没有的话行列式值为0 75 if (pos != k) //将找到的那一行换到第k行,swap(a[k],a[pos]) 76 for (int j = k;j <= n;j++)swap(a[pos][j], a[k][j]); 77 ll inv = niYuan(a[k][k], MOD); 78 for (int i = k + 1;i <= n;i++) 79 if (a[i][k]) 80 { 81 ans = ans * inv % MOD; //下面的计算中第i行提高a[k][k]倍,所以答案需要除以a[k][k]才是正解 82 for (int j = k + 1;j <= n;j++) 83 a[i][j] = ((a[i][j] * a[k][k] % MOD - a[k][j] * a[i][k] % MOD) % MOD + MOD) % MOD; 84 a[i][k] = 0; 85 } 86 } 87 for (int i = 1;i <= n;i++) 88 ans = ans * a[i][i] % MOD; 89 return ans; 90 } 91 92 int A[N], B[N]; 93 94 95 int main() 96 { 97 int t; 98 init(); 99 scanf("%d", &t); 100 while (t--) 101 { 102 int n, k; 103 scanf("%d%d", &n, &k); 104 for (int i = 1;i <= k;i++) scanf("%d", &A[i]); 105 for (int i = 1;i <= k;i++) scanf("%d", &B[i]); 106 107 for (int i = 1;i <= k;i++) 108 { 109 for (int j = 1;j <= k;j++) 110 { 111 a[i][j] = C(n + B[j] - (1 + A[i]), n - 1); 112 } 113 } 114 printf("%lld\n", determinant(k)); 115 } 116 }