生活随笔
收集整理的這篇文章主要介紹了
loj#2143. 「SHOI2017」组合数问题
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
loj#2143. 「SHOI2017」組合數(shù)問題
題目描述
Solution
考慮轉(zhuǎn)化一下我們要求的東西。 ∑i=0n(nkik+r)=∑i=0n(nki)[i≡r(modk)]\sum_{i=0}^{n}\binom{nk}{ik+r}=\sum_{i=0}^{n}\binom{nk}{i}[i \equiv r \;\;(mod\;\;k)] ∑ i = 0 n ? ( i k + r n k ? ) = ∑ i = 0 n ? ( i n k ? ) [ i ≡ r ( m o d k ) ]
這個式子是什么呢? 這不就是nknk n k 個物品中選擇ii i 個物品,且i≡r(modk)i \equiv r\;\;(mod\;\;k) i ≡ r ( m o d k ) 的方案數(shù)嗎?
考慮dpdp d p ,設(shè)fi,jf_{i,j} f i , j ? 表示前ii i 個物品,選擇jj j 個的方案數(shù)(jj j 是在模kk k 意義下的),有: fi,j=fi?1,j+fi?1,(j?1+k)%kf_{i,j}=f_{i-1,j}+f_{i-1,(j-1+k)\%k} f i , j ? = f i ? 1 , j ? + f i ? 1 , ( j ? 1 + k ) % k ? 這里的kk k 只有5050 5 0 ,所以可以直接倍增或者矩陣快速冪優(yōu)化。 我用了矩陣快速冪(直接貼板子就行啦) 時間復(fù)雜度O(k3lg(nk))O(k^3\;lg\;(nk)) O ( k 3 l g ( n k ) )
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second using namespace std
; template < typename T
> inline bool upmin ( T
& x
, T y
) { return y
< x
? x
= y
, 1 : 0 ; }
template < typename T
> inline bool upmax ( T
& x
, T y
) { return x
< y
? x
= y
, 1 : 0 ; } typedef long long ll
;
typedef unsigned long long ull
;
typedef long double lod
;
typedef pair
< int , int > PR
;
typedef vector
< int > VI
; const lod eps
= 1e-11 ;
const lod pi
= acos ( - 1 ) ;
const int oo
= 1 << 30 ;
const ll loo
= 1ll << 62 ;
const int MAXN
= 100005 ;
const int INF
= 0x3f3f3f3f ;
inline int read ( )
{ int f
= 1 , x
= 0 ; char c
= getchar ( ) ; while ( c
< '0' || c
> '9' ) { if ( c
== '-' ) f
= - 1 ; c
= getchar ( ) ; } while ( c
>= '0' && c
<= '9' ) { x
= ( x
<< 3 ) + ( x
<< 1 ) + ( c
^ 48 ) ; c
= getchar ( ) ; } return x
* f
;
}
int n
, mods
, k
, r
;
inline int upd ( int x
, int y
) { return x
+ y
>= mods
? x
+ y
- mods
: x
+ y
; }
struct Matrix
{ int n
, A
[ 55 ] [ 55 ] ; void init ( ) { for ( int i
= 0 ; i
< n
; i
++ ) A
[ i
] [ i
] = 1 ; } Matrix ( int _n
= 0 ) { n
= _n
; memset ( A
, 0 , sizeof A
) ; } Matrix
operator * ( const Matrix
& y
) { Matrix
Ans ( n
) ; for ( int k
= 0 ; k
< n
; k
++ ) for ( int i
= 0 ; i
< n
; i
++ ) for ( int j
= 0 ; j
< n
; j
++ ) Ans
. A
[ i
] [ j
] = upd ( Ans
. A
[ i
] [ j
] , 1ll * A
[ i
] [ k
] * y
. A
[ k
] [ j
] % mods
) ; return Ans
; } Matrix
operator ^ ( ll y
) { Matrix
ret ( n
) , x
= * this ; ret
. init ( ) ; for ( ; y
; y
>>= 1 ) { if ( y
& 1 ) ret
= ret
* x
; x
= x
* x
; } return ret
; } void print ( ) { for ( int i
= 0 ; i
< n
; i
++ ) { for ( int j
= 0 ; j
< n
; j
++ ) cout
<< A
[ i
] [ j
] << " " ; cout
<< endl
; } }
} ;
int main ( )
{ n
= read ( ) , mods
= read ( ) , k
= read ( ) , r
= read ( ) ; Matrix
f ( k
) ; for ( int i
= 0 ; i
< k
; i
++ ) f
. A
[ i
] [ i
] ++ , f
. A
[ i
] [ ( i
+ k
- 1 ) % k
] ++ ; f
= f
^ ( 1ll * n
* k
) ;
printf ( "%d\n" , f
. A
[ 0 ] [ r
] ) ; return 0 ;
}
創(chuàng)作挑戰(zhàn)賽 新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎
總結(jié)
以上是生活随笔 為你收集整理的loj#2143. 「SHOI2017」组合数问题 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。