【问题描述】
azui大爷在quack大爷的带领下开始玩集合了,可是他太懒了,不想做quack大爷布置的作业题,便拿来给你做了:S 集合中有n个不同的元素,我们从1-n标号。考虑S 的子集Si,j,将这些子集排成一个r行c列矩阵的样子。其中第一行为S1,1,S1,2,…,S1,c,第二行为S2,1,S2,2,..,S2,c一直到第r行为Sr,1, Sr,2,…, Sr,c。这些集合还满足对于在一行中左右相邻的两个集右,左侧是右侧的子集,即Si,j∈Si,j+1。这些集合还满足对于在一列中上下相邻的两个集合,上方是下方的子集,即Si,j∈Si+1,j。问对于S 的全部子集,有多少可能的情况排成上述的矩阵(每个子集可以重复使用),结果模109 +7 输出。你一定知道这么简单的题目怎么做,快帮帮azui大爷吧。
【输入格式】
一行三个数n,r,c.
【输出格式】
一个数表示答案。
【样例输入】
1 2 2
【样例输出】
6
【样例解释】
如上图标号后,有:1是2和3的子集,1,2,3都是4的子集。
1
2
3
4
用0表示空集,1表示元素1,从左到右是1、2、3、4的话,有以下6种情况
0000 0001 0011 0101 0111 1111
【数据范围】
对于10%的数据,r*c*n <= 16
对于20%的数据,r*c <= 16, n <= 100
对于另20%的数据,r=1, c<=1000000
对于另10%的数据,n=1
对于100%的数据,r, c <= 1000000, n <= 10^9
题解:线性求逆元:
i*A[i] ≡ 1 (mod p), 求i的逆元A[i]
A[i] ≡ i^(-1) (mod p)
令p=k*i+r ( r<i,1<i<p )
k*i+r≡0 (mod p)
(k*i+r) * i^(−1)*r^(−1) ≡ 0 * i^(−1)*r^(−1) (mod p)
k*r^(−1)+i^(−1) ≡ 0 (mod p)
i^(−1) ≡ -k*r^(−1) (mod p)
i^(−1) ≡ -(p/i)*(p%i)^(−1) (mod p)
即:A[i]=-(p/i)*A[p%i];
#include<cstdio> typedef long long LL; const int Mod=1e9+7; LL n, r, c;LL Mul( LL a, LL b ) {LL res=0;for( int i=1; i<=b; i<<=1, a=(a<<1)%Mod )if( b&i ) res=(res+a)%Mod;return res; }LL Ksm( LL b, LL p ) {LL res=1;while(p) {if( p&1 ) res=Mul( res, b );b=Mul( b, b ); p>>=1;}return res; }LL Fac( LL w ) {//阶乘factorialLL res=1;for( LL i=2; i<=w; i++ ) res=res*i%Mod;return res; }LL Inv( LL w ) {//求逆元if( w==1 ) return 1;return ( Mod-Mod/w*Inv( Mod%w )%Mod )%Mod;//(num+Mod)%Mod避免负数}LL C( LL n, LL m ) {//C( c+r, r )%Modreturn Fac(n) * Inv( Fac(m) )%Mod * Inv( Fac(n-m) )%Mod; /*C(n,m)%Mod == n! / (m!*(n-m)!) % Mod == n! * (m!)^(-1) * ((n-m)!)^(-1) % Mod == n! * Inv(m!) * Inv((n-m)!) % Mod*/ }int main() {scanf( "%I64d%I64d%I64d", &n, &r, &c );printf( "%I64dn", Ksm( C(r+c,r), n ) );return 0; }
本文发布于:2024-01-29 06:41:12,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170648167713429.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |