PID371 / [AHOI1997]彩旗飄飄 排列組合加DP

題目描述

有n面紅旗和n面黃旗從東到西插成一排。如果相鄰的兩面旗幟的顏色不同,則稱爲顏色發生一次改變。

任務:計算這2n面旗幟的顏色改變m次的插法共有多少種?

示例:

旗幟的顏色爲“紅黃紅紅黃黃黃”稱爲顏色改變了3次的插法。

在n=4,m=1時僅有兩種插法:“紅紅紅紅黃黃黃黃”和“黃黃黃黃紅紅紅紅”,對應的輸出爲“2”。

輸入格式

輸入:從鍵盤上依閃輸入自然數n和m。(n<15)

輸出格式

輸出:把插法總數在屏幕上顯示輸出。


插排法

黃色已經排成一排然後向裏面插入紅色發現插入兩邊的變化數+1插入中間變化數+2,所以如果m爲偶數爲只插入中間和兩邊都插得和奇數爲兩邊只插一個的和,然後DP把剩下的棋子插入即可

#include<iostream>
using namespace std;
int dp[20][20]={0};
int C(int n,int m);
int main()
{
int n=0,m=0;
for(int i=0;i<=15;i++)
{
dp[1][i]=1;
dp[i][0]=1;
        dp[i][1]=i;
}
for(int i=2;i<=15;i++)
{
for(int j=0;j<=15;j++)
{
int temp=0;
for(int k=0;k<=j;k++)
{
temp+=dp[i-1][j-k];
}
dp[i][j]=temp;
}
}
while(cin>>n>>m)
{
int sum=0;
if(m&1)
{
sum=sum+2*(C(n-1,(m-1)/2)*dp[1+(m-1)/2][n-1-(m-1)/2]);
}
else
{
sum+=(C(n-1,m/2)*dp[m/2][n-m/2]);
sum+=(C(n-1,m/2-1)*dp[m/2+1][n-m/2-1]);
}
cout<<sum<<endl;
}
return 0;
}
int C(int n,int m)
{
int a=1,b=1;
for(int i=1;i<=m;i++)
{
a*=i;
b*=(n-m+i);
if(b%a==0)
{
b/=a;
a=1;
}
}
return b;
}

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