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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值