UPC-排課表+玉米田(容斥原理+組合數學公式)

排課表

時間限制: 1 Sec 內存限制: 128 MB
[提交] [狀態]
題目描述
新學期伊始,作爲玉米高中的教務主任W某,又要安排學生們的課程表了。

W某想要知道所有可能的排課表方案,於是他開始在紙上列舉所有方案,然而在寫滿了一摞A4紙後,他發現可能的方案太多了——用盡玉米高中所有的A4紙都寫不完。

W某最終放棄了列舉所有方案的想法,但他對排課表的方案數產生了興趣。他的組合數學不太好,所以他找到了正在玉米高中就讀的你,請你幫幫TA。

簡單地說,玉米高中共有T個班級。

對於其中一個班級i,這個班級每天要上mi節互不相同的課,一共有ni節課可供選擇,但這ni節課不能隨便安排,其中也有一些限制:
·有ai節課不能安排在第一節上
·有bi節課不能安排在最後一節上
·沒有任何一節課既不能在第一節上又不能在最後一節上
你需要求出每個班級排課表的方案數除以998244353的餘數。
輸入
第1行包含一個正整數T,表示玉米高中的班級數。

第2行到第T+1行,每行包含四個整數,第i+1行的四個整數ni,mi,ai,bi,分別表示班級i可選的課程數,一天的課程數,不能在第一節上的課程數,不能在最後一節上的課程數。
輸出
輸出T行,第i行表示班級i的排課表方案數除以998244353的餘數。
樣例輸入 Copy
【樣例1】
1
3 2 0 1
【樣例2】
1
5 3 1 1
樣例輸出 Copy
【樣例1】
4
【樣例2】
39
提示
樣例1解釋
設3節可選的課爲a,b,c,其中c不能排在最後一節
4種排課表的方案分別爲:ab,ba,ca,cb

所有測試數據滿足
·1≤T≤104
·2≤mi≤ni≤105
·ai+bi≤ni
思路:
高中排列組合? 劃掉,忘得一乾二淨
今天剛學了容斥原理,但是依稀記得高中好像也是這麼做的
直接計算方案數並不好算,因爲要分類討論很多種情況,我們不妨逆向思維。
用總的方案數 - a放在第一位的方案數 - b放在第一位的方案數 就可以
真的可以嗎?
我們在計算a放在第一位的方案數時,其中有不合法的情況是b在最後一位,同理,我們在計算b放在第一位的方案數時,有不合法的情況是a在第一位,好像減多了呢。
只需要把這一部分加上就可以了~
To be short : 總的方案數-第一節是a的方案數-最後一節是b的方案數+第一節是a而且最後一節是b的方案數
其他的就是高中的知識了
化簡過程就不放了~
在這裏插入圖片描述
解釋一下第二個式子,其他的都類似:
因爲a的位置是確定的,我們首先從a裏選出1個放在首位,此時需要選的還有m-1個,能夠選的還有n-1個,所以就是從n-1裏選m-1個,全排列。
另外,數據較大,需要預處理階乘和逆元
模板:傳送門
代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
const int mod = 998244353;
ll fact[N];//階乘
ll infact[N];//逆元
ll ksm(ll a,ll b,ll p){
    ll res=1;
    while(b){
//&運算當相應位上的數都是1時,該位取1,否則該爲0。
        if(b&1)
            res=1ll*res*a%p;//轉換爲ll型
        a=1ll*a*a%p;
        b>>=1;//十進制下每除10整數位就退一位
    }
    return res;
}
void init(){
    fact[0]=1;
    infact[0]=1;
    for(int i=1;i<N;i++){
        fact[i]=fact[i-1]*i%mod;
        infact[i]=infact[i-1]*ksm(i,mod-2,mod)%mod;
    }
}
int main(){
    init();
    int t;
    cin>>t;
    int n,m,a,b;
    while(t--){
        cin>>n>>m>>a>>b;
        ll res=(fact[n]%mod*infact[n-m]%mod-fact[n-1]%mod*infact[n-m]%mod*(a+b)%mod+fact[n-2]%mod*infact[n-m]%mod*a*b%mod)%mod;
        if(res<0) res+=mod;
        printf("%lld\n",res);
    }
    return 0;
}

玉米田

時間限制: 1 Sec 內存限制: 128 MB
[提交] [狀態]
題目描述
玉米中學的學生社會實踐的內容是去玉米田中種玉米。

玉米中學有n塊不同的玉米田,這些玉米田編號從1到n,且第i號玉米田與第i+1號玉米田相鄰,特殊地,第n號玉米田與第1號玉米田相鄰。

現在玉米中學購置了k種不同的玉米,爲了美觀,學校要求相鄰的玉米田中不能種植同一種玉米,現在W某想要知道種植玉米的方案總數。

由於W某耐心有限,因此只需要你求出對20011021取模後的結果即可。
輸入
一行兩個整數n,k,表示玉米田的數量和玉米的種類數。
輸出
加粗樣式一行一個整數,表示種植玉米的方案數對20011021取模後的結果。
樣例輸入 Copy
【樣例1】
4 2
【樣例2】
4 3
樣例輸出 Copy
【樣例1】
2
【樣例2】
18
提示
樣例1解釋
設2種玉米爲a,b
2種種植玉米的方案爲:abab,baba

所有數據滿足:n,k≤109

直接一波公式:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
const ll mod = 20011021;
ll fact[N];//階乘
ll infact[N];//逆元
ll ksm(ll a,ll b,ll p){
    ll res=1;
    while(b){
//&運算當相應位上的數都是1時,該位取1,否則該爲0。
        if(b&1)
            res=1ll*res*a%p;//轉換爲ll型
        a=1ll*a*a%p;
        b>>=1;//十進制下每除10整數位就退一位
    }
    return res;
}
void init(){
    fact[0]=1;
    infact[0]=1;
    for(int i=1;i<N;i++){
        fact[i]=fact[i-1]*i%mod;
        infact[i]=infact[i-1]*ksm(i,mod-2,mod)%mod;
    }
}
int main(){
    ll n,k;
    cin>>n>>k;
    ll res=((k-1)*ksm(-1,n,mod)%mod+ksm(k-1,n,mod))%mod;
    cout<<res;
    return 0;
}

證明見大佬博客
類似的題:題目鏈接 題解鏈接
好像並不類似(無奈)

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