填格子

Description

  給你一個\(2*m\)的網格,每一個格子必須塗成紅綠藍(\(RGB\))中的一種,要求每一個\(2*2\)的網格中每種顏色都要出現過,而且對於整個網格,任意兩個相鄰的格子顏色不能相同,現給出三種顏色的出現次數,輸出合法的方案數對\(10^9+7\)取模ios

  數據範圍:\(m<=10^6\)c++

  

Solution

  首先注意到由於行數是\(2\)顏色數是\(3\),因此咱們能夠只考慮每一列沒有出現過的顏色個數,記這個組成的序列爲\(A\)spa

  由於\(2*2\)網格中全部的顏色都要出現過一次,因此\(A\)中的相鄰元素必定不一樣,咱們考慮其中一種顏色\(R\),顯然\(R\)將整個\(A\)分紅了若干段,每段只有\(G\)\(B\),考慮這個段數,總共只有三種狀況:\(R+1\)\(R\)\(R-1\),計算的方式相似,咱們能夠計算三次而後把結果加起來code

  假設如今\(GB\)的段數爲\(x\),咱們能夠枚舉其中長度爲奇數的段總共有多少段,而後根據\(G\)\(B\)的出現次數的差,咱們能夠肯定長度爲奇數的段中,形如\(GBG\)的段比\(BGB\)的多多少ip

  而後咱們就能夠直接用組合數計算了,具體一點就是(假設\(B>G\)):
\[ \begin{aligned} tmp&=B-G\\ ans&=\sum\limits_{i=tmp}^x [(i+tmp)\%2==0]\binom x i\cdot\binom i{\frac{i+tmp}{2}}\cdot\binom{\frac{G+B+i}{2}-1}{x-1}\cdot 2^{x-i} \end{aligned} \]
  前面兩個組合數算的是奇數段的,具體就是從\(x\)段中選出\(i\)段做爲奇數段,而後爲了知足\(B\)\(G\)的出現次數差,\(BGB\)的出現次數應該爲\(\frac{i+tmp}{2}\),後面算的是偶數段,爲了保證每段都是偶數因此先集體除以\(2\)而後直接插板,由於有\(GB\)\(BG\)兩種形式因此還要乘上一個\(2^{x-i}\)string

  最後統計答案的時候記得\(R+1\)\(R-1\)的方案數要乘\(2\),由於上下兩行可交換;\(R\)的方案數要乘\(4\),由於除了上下兩行可交換之外\(R\)的段和\(GB\)的段也能夠交換位置it

  

  代碼大概長這個樣子io

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e6+10,MOD=1e9+7;
int fac[N],invfac[N],pw2[N];
int n,m,T,R,G,B;
int ans;
int mul(int x,int y){return 1LL*x*y%MOD;}
int plu(int x,int y){return (1LL*x+y)-(1LL*x+y>=MOD?MOD:0);}
int ksm(int x,int y){
    int ret=1,base=x;
    for (;y;y>>=1,base=mul(base,base))
        if (y&1) ret=mul(ret,base);
    return ret;
}
void prework(int n){
    fac[0]=1;
    for (int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
    invfac[n]=ksm(fac[n],MOD-2);
    for (int i=n-1;i>=0;--i) invfac[i]=mul(invfac[i+1],i+1);
    pw2[0]=1;
    for (int i=1;i<=n;++i) pw2[i]=mul(pw2[i-1],2);
}
int C(int n,int m){return n<m?0:mul(fac[n],mul(invfac[m],invfac[n-m]));}
int calc(int r,int g,int b){
    if (r<=0) return 0;
    int ret=0,tmp=b-g;
    for (int i=tmp;i<=r;++i){
        if ((i+tmp)%2) continue;
        ret=plu(ret,mul(C(r,i),mul(C(i,(i+tmp)/2),mul(C((g+b+i)/2-1,r-1),pw2[r-i]))));
    }
    return ret;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    scanf("%d",&T);
    prework(N-10);
    for (int o=1;o<=T;++o){
        scanf("%d%d%d%d",&n,&R,&G,&B);
        R=n-R; G=n-G; B=n-B;
        if (R>G) swap(R,G);
        if (R>B) swap(R,B);
        if (G>B) swap(B,G);
        ans=mul(2,calc(R-1,G,B));
        ans=plu(ans,mul(4,calc(R,G,B)));
        ans=plu(ans,mul(2,calc(R+1,G,B)));
        printf("%d\n",ans);
    }
}
相關文章
相關標籤/搜索