• [BZOJ1079/Luogu2476][SCOI2008]着色方案


    题目链接:

    BZOJ1079

    Luogu2476

    记忆化搜索+(DP)

    首先看到数据范围就知道状态是个(15^5)的级别而不是(5^{15})了。

    那么显然设(f_{a,b,c,d,e})表示还有(a)种颜色剩(1)个,(b)种剩两个,(cdots)(e)种剩(5)个时的方案数。

    但是如何判断两个颜色不能相邻呢?

    如果记录上一次的颜色,那么这次判断也需要颜色,则状态爆炸。

    发现无论上次是什么颜色,只需要判断是否相同即可。

    那么就记录上一次选的颜色现在还剩几个,在转移时如果相同那么方案数就要少一种选择。

    综上,我们得到了如下的转移式:

    [f_{a,b,c,d,e,PreRem}+=f_{a-1,b,c,d,e,0}*(a-[PreRem==1]) (a>0) ]

    其中(PreRem)代表上一次选的颜色现在剩几个。

    如果还有(a)个颜色(1),那么可以更新答案,(PreRem)变为(0),此时有(a)种颜色可选,故答案(*a)

    同时如果(PreRem==1),那么说明这(a)种颜色中有一种与之前重复,不能选,只剩(a-1)种颜色可选,答案(*(a-1))

    对于其他(4)项转移方程也同理(别忘记在低项加上刚用掉的颜色)。

    时间复杂度 (O(k^c))

    #include <cstdio>
    #include <cstring>
    
    int k,c[10];
    int f[16][16][16][16][16][6];
    const int Mod=1000000007;
    
    int DP(int a,int b,int c,int d,int e,int PreRem)
    {
    	if(!a&&!b&&!c&&!d&&!e)return 1;
    	int &Ans=f[a][b][c][d][e][PreRem];
    	if(~Ans)return Ans;
    	Ans=0;
    	if(a)(Ans+=DP(a-1,b,c,d,e,0)*1LL*(PreRem==1?a-1:a)%Mod)%=Mod;
    	if(b)(Ans+=DP(a+1,b-1,c,d,e,1)*1LL*(PreRem==2?b-1:b)%Mod)%=Mod;
    	if(c)(Ans+=DP(a,b+1,c-1,d,e,2)*1LL*(PreRem==3?c-1:c)%Mod)%=Mod;
    	if(d)(Ans+=DP(a,b,c+1,d-1,e,3)*1LL*(PreRem==4?d-1:d)%Mod)%=Mod;
    	if(e)(Ans+=DP(a,b,c,d+1,e-1,4)*1LL*(PreRem==5?e-1:e)%Mod)%=Mod;
    	return Ans;
    }
    
    int main()
    {
    	scanf("%d",&k),memset(f,-1,sizeof f);
    	for(int cs;k--;)scanf("%d",&cs),++c[cs];
    	printf("%d
    ",DP(c[1],c[2],c[3],c[4],c[5],0));
    	return 0;
    }
    
  • 相关阅读:
    组合容斥计数技巧
    [BZOJ3456]城市规划:DP+NTT+多项式求逆
    [BZOJ4456][ZJOI2016]旅行者:分治+最短路
    [51nod1383&1048]整数分解为2的幂:DP
    [BZO3572][HNOI2014]世界树:虚树+倍增
    树上最小权链覆盖:可并堆
    [BZOJ4237]稻草人:CDQ分治+单调栈
    [BZOJ3453]tyvj 1858 XLkxc:拉格朗日插值
    [BZOJ5463][APIO2018]铁人两项:Tarjan+圆方树
    [BZOJ4695]最假女选手:segment tree beats!
  • 原文地址:https://www.cnblogs.com/LanrTabe/p/10178395.html
Copyright © 2020-2023  润新知