【重慶四校聯考】電路圖A-巴蜀T1(組合數學)

電路圖A

時間限制 : 1s 空間限制 : 256MB 
(A.cpp/c/pas)

【問題描述】

nodgd 要畫一個電路圖。 
這是一個很簡單的電路圖,所有的元件都是串聯關係,從整體來看就是一個環狀的結構。畫電路圖有很多要求,nodgd 爲了畫得好看就又添加了一些額外的要求。所有要求歸結起來有以下幾點: 
1. 這個環狀電路上有n個雙端電路元件(即每個電路元件有兩個 連接導線的接頭),其中只有一個直流電源;爲了本題方便, 
其他 n − 1 個元件都是一模一樣的電阻。 
2. 電流在電路圖中每經過一個元件,就必須拐一個90°的彎;沒有經過元件時不允許拐彎。參考右圖。 
3. 從電路圖整體上觀察,電流沿順時針方向流動,且電路不能自交。參考下圖。 
栗子
栗子 
4. 如果一個符合題意的電路圖,可以通過整體旋轉一定的角度,再適當調整圖中導線的長度,得到另外一個符合題意的電路圖,則這兩個電路圖是相同的。參考下圖。 
還是栗子
那麼問題來了,nodgd想知道有多少種不同的電路圖,以及有多少種不同的美觀電路圖。由於兩個問題的答案都可能很大,請mod 1,000,000,007輸出結果。 
【輸入格式】 
輸入文件A.in。 
輸入文件第一行包含一個正整數n,表示包含電源在內的電路元件的總數量。 
【輸出格式】 
輸出文件A.out。 
輸出文件第一行包含一個整數,表示不同的電路圖數量mod 1,000,000,007的結果。 
第二行包含一個整數,表示不同的美觀電路圖數量mod 1,000,000,007的結果。 
【輸入輸出樣例1】 
A.in 

A.out 


見分發給選手的壓縮文件中的sample\A1.in和sample\A1.ans。 
【輸入輸出樣例1說明】
可以有如下幾種電路圖,電路圖數量是6,所以輸出文件第一行輸出一個整數6; 
容易發現,這6個電路圖都是美觀的電路圖,所以第二行也輸出一個整數6。 

栗子
【輸入輸出樣例2】 
A.in 
10 
A.out 
120 
50


解題報告:

%%%JJDS nodgd

我死也不信NOIP第一題那麼難

把順時針方向看爲正方向

首先由於題目中說每兩個元件之間必須拐90度,因此電路圖可以表示爲一個長度爲n的L和R組成的序列,其中L代表一個左拐,R代表一個右拐

因爲電路圖最後要拐360度回到起點,所以L和R的數量l,r有這麼一個關係:   l = r-4

接下來就成了不同排列的序列個數問題,轉換成計算n中選(n-4)/2個元素的組合數,使用公式Cmn=n!/(m!(n-m)!)

(本來可以用二分數列來O(logn)求階乘,這裏博主懶就不寫了。。。)算組合數+取模運算爲了應對有個小技巧,模除法需要轉換爲乘逆元,求逆元可以用擴展歐幾里得,這裏的p是質數嗎,也可以用logp的費馬小定理(a*a^(p-2) 同餘 1 (mod p)  ,所以a^(p-2)爲a逆元,用快速冪log p求得),下面的代碼使用費馬小定理。

問題一就解決了

問題二:

因爲從內部任何一點都可以看到所有元件,所以不能有向內的矩形凸起,也就是說序列中不能有連續兩個L出現

爲了計算這個限制下的組合方案數,考慮在r個R中插入l個L

因爲這個圖轉化爲的序列是首尾相接的環,所以位置1和位置n不能同爲L,分類討論之後可以得到這個答案等於組合數之差(具體見代碼),


代碼

#include<cstdio>
typedef long long LL;
const LL MOD=1000000007;
LL advpow(LL a,LL b){
    LL ret=1;
    while(b){
        if(b&1)ret*=a,ret%=MOD;
        a*=a;
        a%=MOD;
        b>>=1;
    }
    return ret;
}
LL moddiv(LL a,LL b){
    return (a*advpow(b,MOD-2))%MOD;
}
LL getC(LL a,LL b){
    LL fac1=1,fac2=1;
    for(int i=a+1;i<=b;i++)
        fac1*=i,fac1%=MOD;
    for(int i=b-a;i;i--)
        fac2*=i,fac2%=MOD;
    //printf("fc1:%I64d fc2:%I64d\n",fac1,fac2);
    return moddiv(fac1,fac2);
}
int main(){
    int n;
    scanf("%d",&n);
    int k=(n-4)/2;
    LL p=getC((n+4)/2,n);
    LL ans2=(2LL*getC(k,n-k)-getC(k,n-k-1))%MOD;
    if(ans2<0)ans2+=MOD;
    printf("%lld\n",p);
    printf("%lld\n",ans2);
}

/*
15
   1
   1   1
   1   2   1
   1   3   3   1
   1   4   6   4   1
   1   5  10  10   5   1
   1   6  15  20  15   6   1
   1   7  21  35  35  21   7   1
   1   8  28  56  70  56  28   8   1
   1   9  36  84 126 126  84  36   9   1
   1  10  45 120 210 252 210 120  45  10   1
   1  11  55 165 330 462 462 330 165  55  11   1
   1  12  66 220 495 792 924 792 495 220  66  12   1
   1  13  78 286 715 1287 1716 1716 1287 715 286  78  13   1
   1  14  91 364 1001 2002 3003 3432 3003 2002 1001 364  91  14   1
*/
//忽略這個表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章