多重集合组合数问题 (计数dp)

  • Post author:
  • Post category:其他


题目大意:





n

n






n





种物品,第



i

i






i





种物品有



a

i

a_i







a










i





















个,不同种类的物品可以相互区分但是同一种的物品无法相互区分

求从这些物品种取出



m

m






m





个物品有多少种取法

题目分析:

为了避免重复计数,我们对一种物品尽量一次性拿完,故定义状态:



d

p

[

i

]

[

j

]

dp[i][j]






d


p


[


i


]


[


j


]





为前



i

i






i





种物品取出了



j

j






j





个物品的方案数

考虑转移,前



i

i






i





种物品取出了



j

j






j





个物品这个状态可以由前



i

1

i-1






i













1





种物品取出了



j

k

j-k






j













k





个物品再从第



i

i






i





种物品种选取



k

k






k





个物品转移过来,故有转移方程:





d

p

[

i

+

1

]

[

j

]

=

k

=

0

m

i

n

(

j

,

a

i

)

d

p

[

i

]

[

j

k

]

dp[i+1][j]=\sum_{k=0} ^{min(j,a_i)} dp[i][j-k]






d


p


[


i




+








1


]


[


j


]




=

















k


=


0



















m


i


n


(


j


,



a










i


















)




















d


p


[


i


]


[


j













k


]







此转移方程的时间复杂度显然为



O

(

n

m

2

)

O(n*m^2)






O


(


n














m










2









)





,复杂度不太优秀

那么继续考虑优化,我们发现求和上界



m

i

n

(

j

,

a

i

)

min(j,a_i)






m


i


n


(


j


,





a










i


















)





可以分为两种情况:




  1. j

    a

    i

    j \le a_i






    j














    a










    i





















    ,将求和公式部分展开取出



    d

    p

    [

    i

    ]

    [

    j

    ]

    dp[i][j]






    d


    p


    [


    i


    ]


    [


    j


    ]





    再化成求和公式的形式




    k

    =

    0

    m

    i

    n

    (

    j

    ,

    a

    i

    )

    d

    p

    [

    i

    ]

    [

    j

    k

    ]

    \sum_{k=0} ^{min(j,a_i)} dp[i][j-k]



















    k


    =


    0










    m


    i


    n


    (


    j


    ,



    a










    i


















    )





















    d


    p


    [


    i


    ]


    [


    j













    k


    ]









    =

    k

    =

    0

    j

    d

    p

    [

    i

    ]

    [

    j

    k

    ]

    = \sum_{k=0} ^j dp[i][j-k]






    =





















    k


    =


    0









    j




















    d


    p


    [


    i


    ]


    [


    j













    k


    ]









    =

    d

    p

    [

    i

    ]

    [

    j

    ]

    +

    d

    p

    [

    i

    ]

    [

    j

    1

    ]

    +

    .

    .

    .

    +

    d

    p

    [

    i

    ]

    [

    0

    ]

    = dp[i][j]+dp[i][j-1]+…+dp[i][0]






    =








    d


    p


    [


    i


    ]


    [


    j


    ]




    +








    d


    p


    [


    i


    ]


    [


    j













    1


    ]




    +








    .


    .


    .




    +








    d


    p


    [


    i


    ]


    [


    0


    ]









    =

    d

    p

    [

    i

    ]

    [

    j

    ]

    +

    k

    =

    0

    j

    1

    d

    p

    [

    i

    ]

    [

    j

    1

    k

    ]

    = dp[i][j]+\sum_{k=0} ^{j-1} dp[i][j-1-k]






    =








    d


    p


    [


    i


    ]


    [


    j


    ]




    +





















    k


    =


    0










    j





    1





















    d


    p


    [


    i


    ]


    [


    j













    1













    k


    ]










    k

    =

    0

    j

    1

    d

    p

    [

    i

    ]

    [

    j

    1

    k

    ]

    \sum_{k=0} ^{j-1} dp[i][j-1-k]



















    k


    =


    0










    j





    1





















    d


    p


    [


    i


    ]


    [


    j













    1













    k


    ]





    带回状态转移方程有




    k

    =

    0

    j

    1

    d

    p

    [

    i

    ]

    [

    j

    1

    k

    ]

    \sum_{k=0} ^{j-1} dp[i][j-1-k]



















    k


    =


    0










    j





    1





















    d


    p


    [


    i


    ]


    [


    j













    1













    k


    ]









    =

    k

    =

    0

    j

    1

    ,

    a

    I

    d

    p

    [

    i

    ]

    [

    (

    j

    1

    )

    k

    ]

    = \sum_{k=0} ^{j-1,a_I} dp[i][(j-1)-k]






    =





















    k


    =


    0










    j





    1


    ,



    a










    I





































    d


    p


    [


    i


    ]


    [


    (


    j













    1


    )













    k


    ]









    =

    d

    p

    [

    i

    +

    1

    ]

    [

    j

    1

    ]

    = dp[i+1][j-1]






    =








    d


    p


    [


    i




    +








    1


    ]


    [


    j













    1


    ]






    故在此时有



    d

    p

    [

    i

    +

    1

    ]

    [

    j

    ]

    =

    d

    p

    [

    i

    ]

    [

    j

    ]

    +

    d

    p

    [

    i

    +

    1

    ]

    [

    j

    1

    ]

    dp[i+1][j] = dp[i][j]+dp[i+1][j-1]






    d


    p


    [


    i




    +








    1


    ]


    [


    j


    ]




    =








    d


    p


    [


    i


    ]


    [


    j


    ]




    +








    d


    p


    [


    i




    +








    1


    ]


    [


    j













    1


    ]







  2. j

    >

    a

    i

    j \gt a_i






    j




    >









    a










    i





















    ,将求和公式部分展开取出



    d

    p

    [

    i

    ]

    [

    j

    ]

    dp[i][j]






    d


    p


    [


    i


    ]


    [


    j


    ]









    d

    p

    [

    i

    ]

    [

    j

    1

    a

    i

    ]

    dp[i][j-1-a_i]






    d


    p


    [


    i


    ]


    [


    j













    1














    a










    i


















    ]





    再化成求和公式的形式(为了方便推导增加式子



    d

    p

    [

    i

    ]

    [

    j

    1

    a

    [

    i

    ]

    ]

    d

    p

    [

    i

    ]

    [

    j

    1

    a

    [

    i

    ]

    ]

    dp[i][j-1-a[i]] – dp[i][j-1-a[i]]






    d


    p


    [


    i


    ]


    [


    j













    1













    a


    [


    i


    ]


    ]













    d


    p


    [


    i


    ]


    [


    j













    1













    a


    [


    i


    ]


    ]





    ,因为



    j

    >

    a

    i

    j \gt a_i






    j




    >









    a










    i





















    故在



    j

    1

    a

    i

    j-1-a_i






    j













    1














    a










    i





















    时才会为0所以数组不会越界)




    k

    =

    0

    m

    i

    n

    (

    j

    ,

    a

    i

    )

    d

    p

    [

    i

    ]

    [

    j

    k

    ]

    \sum_{k=0} ^{min(j,a_i)} dp[i][j-k]



















    k


    =


    0










    m


    i


    n


    (


    j


    ,



    a










    i


















    )





















    d


    p


    [


    i


    ]


    [


    j













    k


    ]









    =

    k

    =

    0

    a

    i

    d

    p

    [

    i

    ]

    [

    j

    k

    ]

    = \sum_{k=0} ^{a_i} dp[i][j-k]






    =





















    k


    =


    0











    a










    i





































    d


    p


    [


    i


    ]


    [


    j













    k


    ]









    =

    d

    p

    [

    i

    ]

    [

    j

    ]

    +

    d

    p

    [

    i

    ]

    [

    j

    1

    ]

    +

    .

    .

    .

    +

    d

    p

    [

    i

    ]

    [

    j

    a

    i

    ]

    = dp[i][j]+dp[i][j-1]+…+dp[i][j-a_i]






    =








    d


    p


    [


    i


    ]


    [


    j


    ]




    +








    d


    p


    [


    i


    ]


    [


    j













    1


    ]




    +








    .


    .


    .




    +








    d


    p


    [


    i


    ]


    [


    j














    a










    i


















    ]









    =

    d

    p

    [

    i

    ]

    [

    j

    ]

    +

    d

    p

    [

    i

    ]

    [

    j

    1

    ]

    +

    .

    .

    .

    +

    d

    p

    [

    i

    ]

    [

    j

    a

    i

    ]

    +

    d

    p

    [

    i

    ]

    [

    j

    1

    a

    i

    ]

    d

    p

    [

    i

    ]

    [

    j

    a

    i

    1

    ]

    = dp[i][j]+dp[i][j-1]+…+dp[i][j-a_i]+dp[i][j-1-a_i]-dp[i][j-a_i-1]






    =








    d


    p


    [


    i


    ]


    [


    j


    ]




    +








    d


    p


    [


    i


    ]


    [


    j













    1


    ]




    +








    .


    .


    .




    +








    d


    p


    [


    i


    ]


    [


    j














    a










    i


















    ]




    +








    d


    p


    [


    i


    ]


    [


    j













    1














    a










    i


















    ]













    d


    p


    [


    i


    ]


    [


    j














    a










    i





























    1


    ]






    取出



    d

    p

    [

    i

    ]

    [

    j

    ]

    dp[i][j]






    d


    p


    [


    i


    ]


    [


    j


    ]









    d

    p

    [

    i

    ]

    [

    j

    1

    a

    i

    ]

    -dp[i][j-1-a_i]









    d


    p


    [


    i


    ]


    [


    j













    1














    a










    i


















    ]





    对剩下的求和带入转移方程有:




    d

    p

    [

    i

    ]

    [

    j

    1

    ]

    +

    d

    p

    [

    i

    ]

    [

    j

    2

    ]

    +

    .

    .

    .

    +

    d

    p

    [

    i

    ]

    [

    j

    1

    a

    i

    ]

    dp[i][j-1]+dp[i][j-2]+…+dp[i][j-1-a_i]






    d


    p


    [


    i


    ]


    [


    j













    1


    ]




    +








    d


    p


    [


    i


    ]


    [


    j













    2


    ]




    +








    .


    .


    .




    +








    d


    p


    [


    i


    ]


    [


    j













    1














    a










    i


















    ]









    =

    k

    =

    0

    a

    i

    d

    p

    [

    i

    ]

    [

    (

    j

    1

    )

    +

    k

    ]

    =\sum_{k=0}^{a_i}dp[i][(j-1)+k]






    =





















    k


    =


    0











    a










    i





































    d


    p


    [


    i


    ]


    [


    (


    j













    1


    )




    +








    k


    ]









    =

    d

    p

    [

    i

    +

    1

    ]

    [

    j

    1

    ]

    =dp[i+1][j-1]






    =








    d


    p


    [


    i




    +








    1


    ]


    [


    j













    1


    ]






    故在此时有



    d

    p

    [

    i

    +

    1

    ]

    [

    j

    ]

    =

    d

    p

    [

    i

    ]

    [

    j

    ]

    +

    d

    p

    [

    i

    +

    1

    ]

    [

    j

    1

    ]

    d

    p

    [

    i

    ]

    [

    j

    1

    a

    i

    ]

    dp[i+1][j] = dp[i][j] + dp[i+1][j-1] – dp[i][j-1-a_i]






    d


    p


    [


    i




    +








    1


    ]


    [


    j


    ]




    =








    d


    p


    [


    i


    ]


    [


    j


    ]




    +








    d


    p


    [


    i




    +








    1


    ]


    [


    j













    1


    ]













    d


    p


    [


    i


    ]


    [


    j













    1














    a










    i


















    ]




综合上述两种情况转移方程可以化简为:

if(j <= a[i]) dp[i][j] = dp[i-1][j]+dp[i][j-1]
else dp[i][j] = dp[i-1][j]+dp[i][j-1]+dp[i-1][j-1-a[i]]

此方程复杂度为



O

(

n

m

)

O(nm)






O


(


n


m


)






再思考状态



d

p

[

i

]

[

j

]

dp[i][j]






d


p


[


i


]


[


j


]





其空间复杂度为



O

(

n

m

)

O(nm)






O


(


n


m


)





,我们发现在转移时我们只关心这一行和上一行的元素而不关心其他行的元素故可以对第一维



i

 

m

o

d

 

2

i \ mod \ 2






i




m


o


d




2





,空间复杂度就能优化到



O

(

m

)

O(m)






O


(


m


)




例题:poj-3046Ant Counting

题目链接:

点击这里


具体细节见代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int mod = 1e6;
int id,ans,dp[2][100005],x[1005];
int main()
{
	int t = read(),a = read(),s = read(),b = read();
	for(int i = 1;i <= a;i++)
	{
		id = read();
		x[id]++;
	}
	dp[0][0] = dp[1][0] = 1;
	for(int i = 1;i <= t;i++) 
	for(int j = 1;j <= b;j++)
	{
		if(j <= x[i])
		dp[i%2][j] = (dp[(i-1)%2][j]+dp[i%2][j-1])%mod;
		else 
		dp[i%2][j] = (dp[(i-1)%2][j]+dp[i%2][j-1]-dp[(i-1)%2][j-1-x[i]]+mod)%mod;
	}
	for(int i = s;i <= b;i++) 
		ans = (ans+dp[t%2][i])%mod;
	printf("%d\n",ans);
	return 0;
}



版权声明:本文为qq_39641976原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。