Gaius Julius Caesar, a famous general, loved to line up his soldiers. Overall the army had n1 footmen and n2 horsemen. Caesar thought that an arrangement is not beautiful if somewhere in the line there are strictly more that k1 footmen standing successively one after another, or there are strictly more than k2 horsemen standing successively one after another. Find the number of beautiful arrangements of the soldiers.
Note that all n1 + n2 warriors should be present at each arrangement. All footmen are considered indistinguishable among themselves. Similarly, all horsemen are considered indistinguishable among themselves.
The only line contains four space-separated integers n1, n2, k1, k2 (1 ≤ n1, n2 ≤ 100, 1 ≤ k1, k2 ≤ 10) which represent how many footmen and horsemen there are and the largest acceptable number of footmen and horsemen standing in succession, correspondingly.
Print the number of beautiful arrangements of the army modulo 100000000 (108). That is, print the number of such ways to line up the soldiers, that no more than k1 footmen stand successively, and no more than k2 horsemen stand successively.
2 1 1 10
1
2 3 1 2
5
2 4 1 1
0
Let's mark a footman as 1, and a horseman as 2.
In the first sample the only beautiful line-up is: 121
In the second sample 5 beautiful line-ups exist: 12122, 12212, 21212, 21221, 22121
题目大意:
有n1个数字1,有n2个数字2(看的Note翻译的,不知道原文是不是也是这样)
将n1+n2个数字排成一排,其中要求连续的数字1最多可以有k1个,连续的数字2最多有k2个。
问一共有多少种分配方案。
思路:
1、统计计数问题,考虑dp。
设定dp【i】【j1】【j2】【k1】【k2】【l(2)】,表示dp到第i位,当前数字类型是l,其中数字1使用了j1个,数字2使用了j2个,并且最后一个数字(当前数字)之前的连续l(假设是0)一共有k1个,再之前连续的另外一种数字一共有k2个的方案数。明显能够包含住所有的情况,因为内存限制包括时间限制,我们考虑将这个数组降低维度。
我们其实只考虑当前数字的情况即可,那么:
设定dp【i】【j】【k】【l(2)】,表示当前dp到第i位,当前数字类型是l,对应当前数字l已经使用了j个,并且最后一个数字(当前数字)之前连续的l一共有k个的方案数。
2、设定好dp数组之后,考虑递推出其状态转移方程(此时我们l==0表示上边添加的数字为1,l==1表示上边天剑的数字为2):
if(k==1)
dp【i】【j】【k】【0】+=dp【i-1】【i-j】【kk】【1】;
表示我们当前第i位子上的数和第i-1位子上的数不同,那么对应我们需要考虑上一位子的状态,首先我们知道,在第i-1位子上的时候,一共有数字i-1个,对应其中一定包含j-1个数字1,那么其包含数字2的个数为:i-1-(j-1)=i-j;那么此时我们需要再枚举这样一个变量:因为我们此时第i-1位子上的数字要是2,那么我们需要知道此时连续的2的个数。那么我们再枚举一个kk即可。
if(k>1)
dp【i】【j】【k】【0】+=dp【i-1】【j-1】【k-1】【0】;
表示我们当前第i位子上的数和第i-1位子上的数相同,那么对应我们上一位子的状态:dp到第i-1位,已经使用数字1的个数为j-1个,对应连续的数字1的个数为k-1.直接累加上即可。
同理,对应有:
if(k==1)
dp【i】【j】【k】【1】+=dp【i-1】【i-j】【kk】【0】;
if(k>1)
dp【i】【j】【k】【1】+=dp【i-1】【j-1】【k-1】【1】;
3、注意对1e8取模,注意初始化,其他的就没有什么了。
Ac代码:
#include<stdio.h>
#include<string.h>
using namespace std;
#define mod 100000000
int dp[225][125][15][2];
int main()
{
int n1,n2,k1,k2;
while(~scanf("%d%d%d%d",&n1,&n2,&k1,&k2))
{
memset(dp,0,sizeof(dp));
dp[1][1][1][0]=1;
dp[1][1][1][1]=1;
for(int i=2;i<=n1+n2;i++)
{
//////当前第i位子上的数字是0;
for(int j=1;j<=i&&j<=n1;j++)
{
for(int k=1;k<=j&&k<=k1;k++)
{
if(k==1)
{
for(int kk=1;kk<=k2;kk++)
{
dp[i][j][k][0]+=dp[i-1][i-j][kk][1];
dp[i][j][k][0]%=mod;
}
}
else
dp[i][j][k][0]+=dp[i-1][j-1][k-1][0];
dp[i][j][k][0]%=mod;
}
}
//当前第i个位子上的数字是1
for(int j=1;j<=i&&j<=n2;j++)
{
for(int k=1;k<=j&&k<=k2;k++)
{
if(k==1)
{
for(int kk=1;kk<=k1;kk++)
{
dp[i][j][k][1]+=dp[i-1][i-j][kk][0];
dp[i][j][k][1]%=mod;
}
}
else
dp[i][j][k][1]+=dp[i-1][j-1][k-1][1];
dp[i][j][k][1]%=mod;
}
}
}
int output=0;
for(int i=1;i<=k1;i++)
{
output+=dp[n1+n2][n1][i][0];
output%=mod;
}
for(int i=1;i<=k2;i++)
{
output+=dp[n1+n2][n2][i][1];
output%=mod;
}
printf("%d\n",output);
}
}
探讨了在给定数量的步兵和骑兵以及连续排列的最大数量限制下,如何计算满足条件的不同排列方式总数的问题。
2311

被折叠的 条评论
为什么被折叠?



