日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数论三之排列组合Ⅱ——Virus Tree 2,RGB Coloring,123 Triangle,排列计数,排队,卡农

發布時間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数论三之排列组合Ⅱ——Virus Tree 2,RGB Coloring,123 Triangle,排列计数,排队,卡农 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

絲且人一口

  • Virus Tree 2
    • description
    • solution
    • code
  • RGB Coloring
    • description
    • solution
    • code
  • 123 Triangle
    • description
    • solution
    • code
  • [SDOI2016]排列計數
    • description
    • solution
    • code
  • [HNOI2012]排隊
    • description
    • solution
    • code
  • [HNOI2011]卡農
    • description
    • solution
    • code

Virus Tree 2

description

solution

距離不超過222的點,可能是兒子/孫子/父親/爺爺

考慮從上到下,由上面的顏色選取決定下面的顏色

顯然,第一個點有KKK種選擇,第二個點有K?1K-1K?1種,每次不同都要?1-1?1

答案就是每個點的選擇的乘積

所以只需要把這種過程的遞減通過dfs樹來實現

對于現在的子樹根節點uuu,如果vvv是第一個兒子,那么需要考慮vvv有沒有爺爺

如果不是第一個兒子,那么就是前一個兒子的方案數再?1-1?1

code

#include <cstdio> #include <vector> using namespace std; #define mod 1000000007 #define int long long #define maxn 1000005 vector < int > G[maxn]; int n, k; int w[maxn];void dfs( int u, int fa ) {int r = 0;for( auto v : G[u] ) {if( v == fa ) continue;else {if( r ) w[v] = r - 1;else if( ! fa ) w[v] = k - 1;else w[v] = k - 2;r = w[v]; }}for( auto v : G[u] ) if( v ^ fa ) dfs( v, u ); }signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );}w[1] = k;dfs( 1, 0 );int ans = 1;for( int i = 1;i <= n;i ++ )if( w[i] <= 0 ) return ! printf( "0\n" );else ans = ans * w[i] % mod;printf( "%lld\n", ans );return 0; }

RGB Coloring

description

solution

將綠色A+BA+BA+B看成既涂了紅色AAA,又涂了藍色BBB,則紅色和藍色格子彼此獨立,就算涂在同一個格子上也沒關系

枚舉紅色格子的數量iii,計算得出藍色格子數量j=K?A×iBj=\frac{K-A\times i}{B}j=BK?A×i?

判斷格子數量為整數且都在nnn以內即可,然后用組合計數從nnn個格子中選紅/藍色

∑Cni×Cnj\sum C_n^i\times C_n^jCni?×Cnj?

code

#include <cstdio> #define int long long #define mod 998244353 #define maxn 300005 int n, A, B, k; int fac[maxn], inv[maxn];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }void init() {fac[0] = inv[0] = 1;for( int i = 1;i <= n;i ++ )fac[i] = fac[i - 1] * i % mod;inv[n] = qkpow( fac[n], mod - 2 );for( int i = n - 1;i;i -- )inv[i] = inv[i + 1] * ( i + 1 ) % mod; }int C( int n, int m ) {if( m < 0 || n < m ) return 0;else return fac[n] * inv[m] % mod * inv[n - m] % mod; }signed main() {scanf( "%lld %lld %lld %lld", &n, &A, &B, &k );init();int ans = 0; for( int i = 0, j;i <= n;i ++ ) {if( ( k - A * i ) % B ) continue;else j = ( k - A * i ) / B;ans = ( ans + C( n, i ) * C( n, j ) ) % mod;}printf( "%lld\n", ans );return 0; }

123 Triangle

description

solution

N>1N>1N>1式子是差分形式,后面序列只有能是0/1/20/1/20/1/2

(除非N=1N=1N=1的情況答案有可能是333

如果此時序列有111,那么答案一定只能是0/10/10/1,因為0/20/20/2碰到111都會變成111

如果序列沒有111,則答案只會是0/20/20/2,對于這種情況,將每個數/2/2/2得到結果后再×2\times 2×2是等價的

所以現在的答案都只會是0/10/10/1,考慮在(mod2)\pmod 2(mod2)意義下做

(mod2)\pmod 2(mod2)的情況下,加減法可以看成二進制的異或

所求即為一段序列相鄰兩個數異或直到最后成一個數的答案

考慮每個數被異或的次數,這其實是個倒楊輝三角(0,0)(0,0)(0,0)開始

長為nnn的序列的第iii個元素被異或的次數為Cn?1i?1C_{n-1}^{i-1}Cn?1i?1?

計算在模222意義下(除法不一定有逆元)的組合數

  • 計算每個階乘中分解222的次數,將除法變成減法,對于組合數最后剩下的222的次數為000,則為1(mod2)1\pmod 21(mod2),反之0(mod2)0\pmod 20(mod2)
  • 階乘的分解,拆分成對每個數求出分解中222的次數,做前綴和

code

#include <cmath> #include <cstdio> #define maxn 1000005 int n; char s[maxn]; int x[maxn], cnt[maxn]; int main() {scanf( "%d %s", &n, s + 1 );n --;for( int i = 1;i <= n;i ++ )x[i] = fabs( s[i] - s[i + 1] );bool flag = 1;for( int i = 1;i <= n;i ++ )if( x[i] == 1 ) { flag = 0; break; }if( flag ) for( int i = 1;i <= n;i ++ )x[i] >>= 1;for( int i = 1;i <= n;i ++ ) {int t = i;while( ! ( t & 1 ) ) t >>= 1, cnt[i] ++;cnt[i] += cnt[i - 1];}int ans = 0;for( int i = 1;i <= n;i ++ )ans ^= cnt[n - 1] - cnt[i - 1] - cnt[n - i] ? 0 : ( x[i] & 1 );if( flag ) ans <<= 1;printf( "%d", ans );return 0; }

[SDOI2016]排列計數

description

solution

組合數從nnn個中選mmm個強制ai=ia_i=iai?=i,剩下的n?mn-mn?mai≠ia_i≠iai??=i,就是n?mn-mn?m的錯排數

code

#include <cstdio> #define mod 1000000007 #define int long long #define maxn 1000005 int fac[maxn], inv[maxn], D[maxn]; int T, n, m;int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }void init() {fac[0] = inv[0] = 1;for( int i = 1;i < maxn;i ++ )fac[i] = fac[i - 1] * i % mod;inv[maxn - 1] = qkpow( fac[maxn - 1], mod - 2 );for( int i = maxn - 2;i;i -- )inv[i] = inv[i + 1] * ( i + 1 ) % mod;D[0] = 0, D[1] = 0, D[2] = 1;for( int i = 3;i < maxn;i ++ )D[i] = ( D[i - 1] + D[i - 2] ) * ( i - 1 ) % mod; }int C( int n, int m ) {return fac[n] * inv[m] % mod * inv[n - m] % mod; }signed main() {init();scanf( "%lld", &T );while( T -- ) {scanf( "%lld %lld", &n, &m );if( n == m ) printf( "1\n" ); else printf( "%lld\n", C( n, m ) * D[n - m] % mod );}return 0; }

[HNOI2012]排隊

description

solution

不給模數還明示答案可能很大,赤裸裸的大整數脅迫!!居心叵測!!

兩名老師真的是很煩了,沒有這么討人厭的老師,可以直接女生插板法了

  • 兩名老師之間是男生

    先排男生AnnA_n^nAnn?,產生n+1n+1n+1個空

    再插板兩名老師,An+12A_{n+1}^2An+12?,產生n+3n+3n+3個空

    最后插板mmm名女生,An+3mA_{n+3}^mAn+3m?

  • 兩名老師之間是女生

    先排男生AnnA_n^nAnn?

    再打包兩名老師放同一個隔板里,老師間還有順序,A22Cn+11A_2^2C_{n+1}^1A22?Cn+11?

    先強制選一名女生放進老師中間mmm,剩下的就隔板插

    男生nnn個,老師和強制女生打包裝成一個,總共是n+1n+1n+1個,產生n+2n+2n+2個空,An+2m?1A_{n+2}^{m-1}An+2m?1?

綜上,ans=AnnAn+12An+3m+A22Cn+11An+2m?1ans=A_n^nA_{n+1}^2A_{n+3}^m+A_2^2C_{n+1}^1A_{n+2}^{m-1}ans=Ann?An+12?An+3m?+A22?Cn+11?An+2m?1?

同樣,老師不相鄰===不考慮老師?-?老師相鄰

  • 不考慮老師

    把老師當成男的,女的直接插,An+2n+2An+3mA_{n+2}^{n+2}A_{n+3}^mAn+2n+2?An+3m?

  • 老師相鄰

    捆綁法強制兩名老師一起當成一個男的A22An+1n+1An+2mA_2^2A_{n+1}^{n+1}A_{n+2}^mA22?An+1n+1?An+2m?

二者做差就是答案

code

#include <cstdio> #include <cstring> #include <iostream> using namespace std; int n, m;struct Int {int g[20000], len;Int() {memset( g, 0, sizeof( g ) );len = 0;}Int( int x ) {memset( g, 0, sizeof( g ) );len = 0;if( ! x ) len = 1;else while( x ) g[len ++] = x % 10, x /= 10;}void clean() {while( len > 1 && ! g[len - 1] ) len --;}Int operator - ( Int t ) {Int ans;ans.len = len;for( int i = 0;i < t.len;i ++ ) {ans.g[i] = g[i] - t.g[i];if( ans.g[i] < 0 ) ans.g[i] += 10, g[i + 1] --;}for( int i = t.len;i < len;i ++ )ans.g[i] = g[i]; ans.clean();return ans;}Int operator * ( Int t ) {Int ans;ans.len = len + t.len;for( int i = 0;i < len;i ++ )for( int j = 0;j < t.len;j ++ )ans.g[i + j] += g[i] * t.g[j];for( int i = 0;i < ans.len;i ++ )ans.g[i + 1] += ans.g[i] / 10, ans.g[i] %= 10;ans.len ++;ans.clean();return ans;} void print() {for( int i = len - 1;~ i;i -- )printf( "%d", g[i] );}};Int calc( int n, int m ) {Int ans = ( 1 );for( int i = n - m + 1;i <= n;i ++ )ans = ans * i;return ans; }int main() {scanf( "%d %d", &n, &m );Int ans;ans = calc( n + 2, n + 2 ) * calc( n + 3, m ) - calc( 2, 2 ) * calc( n + 1, n + 1 ) * calc( n + 2, m ); ans.print();return 0; }

[HNOI2011]卡農

description

solution

同種音樂其實通過除以m!m!m!就可以消掉

相當于在SSS中選mmm個子集,滿足

  • 子集非空
  • 不存在兩個完全一樣的子集
  • ?i,i∈[1,n]\forall_{i,i\in[1,n]}?i,i[1,n]?每個元素出現次數為偶數

fi:f_i:fi?: 考慮iii個子集,滿足以上所有性質的方案數

  • 如果知道i?1i-1i?1個子集的,那么iii個子集的集合就被確定了下來A2n?1i?1A_{2^n-1}^{i-1}A2n?1i?1?
  • 如果子集是空,那么去掉這個子集剩下的i?1i-1i?1個子集是合法方案fi?1f_{i-1}fi?1?
  • 如果iii子集與jjj子集重復,jjji?1i-1i?1種選擇,剔除這兩個子集剩下i?2i-2i?2子集是合法的fi?2f_{i-2}fi?2?iii子集選擇有2n?1?(i?2)2^n-1-(i-2)2n?1?(i?2)(排除掉剩下i?2i-2i?2個子集,不能與之重復)

最后別忘了m!m!m!

code

#include <cstdio> #define mod 100000007 #define int long long #define maxn 1000005 int n, m; int A[maxn], f[maxn];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }signed main() {scanf( "%lld %lld", &n, &m );f[0] = 1, f[1] = 0;int t = ( qkpow( 2, n ) - 1 + mod ) % mod;A[0] = 1;for( int i = 1;i <= m;i ++ )A[i] = ( A[i - 1] * ( t - i + 1 ) % mod + mod ) % mod;int MS = 1;for( int i = 2;i <= m;i ++ ) {f[i] = ( A[i - 1] - f[i - 1] - f[i - 2] * ( i - 1 ) % mod * ( t - i + 2 ) % mod ) % mod;MS = MS * i % mod;}printf( "%lld\n", ( f[m] + mod ) % mod * qkpow( MS, mod - 2 ) % mod );return 0; }

總結

以上是生活随笔為你收集整理的数论三之排列组合Ⅱ——Virus Tree 2,RGB Coloring,123 Triangle,排列计数,排队,卡农的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。