• Codeforces 140E(排列组合、dp)


    要点

    • 主要学到的东西:一个序列染色,相邻不染同色,恰用(j)种颜色的1.模式数2.方案数3.具体染色数
    • 从大的思路上来讲:先dp预处理出每一层的模式数:(f[i][j])表示(i)个位置恰染(j)个颜色的模式数,然后再dp出各层之间的转移:(dp[i][j])表示(i)层恰染(j)个颜色的具体染色数,用上一轮的答案乘上这一层的具体染色数(是(f[l[i]][j]*A_m^j)再减去这层和上层重复的。
    • 我将染色的阶段分为三个阶段。虽然题目中总是让求方案数但不同的题需要的是不同阶段的方案数。
    • 第一阶段是模式数:即如果有三个位置,你决定填充的是“红绿红”和“绿红绿”其实是一样的“模式”。本题预处理的就是模式:(f[i][j] = f[i-1][j-1]+f[i-1][j]*(j-1)),意义是前i-1个如果已经有使用过j-1种类型,则这个位置是唯一的(*1);如果前i-1个已经使用过j种类型,则当前的只要和相邻的左边这个不同即可。
    • 第二阶段是方案数,即“这个类型用第几个颜色去填充它”,更具体了一些。这时“红绿红”和“绿红绿”就是典型的两种方案。第二阶段的计算方法是:(f[i][j]*j!)。之前做的一道题GYM 101933K他官方题解的做法(方法二)就是直接进行第二阶段的记忆化搜索,我用这套理论先递推第一阶段再做第二阶段(乘个阶乘),果然也是对的。
    • 第三阶段是具体染色数,即真的给了赤橙黄绿青蓝紫然后选若干个去染,就最最具体的阶段了。计算方法:(f[i][j]*j!*C_m^j=f[i][j]*A_m^j)
    • 这些还没说完orz……这题真的想了很久。回到本题,其中扣掉“这层和上层重复的”这里我觉得有必要想一想,扣的方案数是第几阶段的方案数?正解是(dp[i][j]-dp[i-1][j]*j!*f[l[i]][j]),为什么是(j!)而不是(A_m^j)或者(C_m^j)呢?因为当你已经计算完上一层的方案数之时,回想数学课学习的排列组合知识,是不是就假定了上一层已经固定了?虽然不知道固定的是谁,但是他已经有了一定了。所以这一层如果跟上一层颜色集重合的话,就是(1*方案数),即上一层如果是“红绿”的话,这一层也只有选择“红绿”时才会和它重,所以只扣一份的即可。
    #include <cstdio>
    
    const int maxn = 1e6 + 5;
    int n, m, p, l[maxn];
    int f[5005][5005], A[5005], fac[5005];
    int dp[2][5005], ans[2];
    
    void Read() {
    	scanf("%d %d %d", &n, &m, &p);
    	for (int i = 1; i <= n; i++)
    		scanf("%d", &l[i]);
    }
    
    void Pre() {
    	f[0][0] = 1;
    	for (int i = 1; i <= 5000; i++)
    		for (int j = 1; j <= i; j++)
    			f[i][j] = (1LL * f[i - 1][j - 1] + 1LL * f[i - 1][j] * (j - 1) % p) % p;
    
    	fac[0] = A[0] = 1;
    	for (int i = 1; i <= 5000; i++) {
    		fac[i] = 1LL * fac[i - 1] * i % p;
    		A[i] = 1LL * A[i - 1] * (m - i + 1) % p;
    	}
    }
    
    void Solve() {
    	ans[0] = 1;
    	for (int i = 1; i <= n; i++) {
    		ans[i & 1] = 0;
    		for (int j = 1; j <= l[i]; j++) {
    			dp[i & 1][j] = 1LL * A[j] * f[l[i]][j] % p * ans[(i - 1) & 1] % p;
    			if (j <= l[i - 1]) {
    				int out = 1LL * dp[(i - 1) & 1][j] * fac[j] % p * f[l[i]][j] % p;
    				dp[i & 1][j] = (dp[i & 1][j] - out + p) % p;
    			}
    			
    			ans[i & 1] = (ans[i & 1] + dp[i & 1][j]) % p;
    		}
    	}
    }
    
    int main() {
    	Read();
    	Pre();
    	Solve();
    	return !printf("%d
    ", ans[n & 1]);
    }
    
  • 相关阅读:
    [Kafka]
    [Kafka]
    [数据挖掘]
    接口部署说明
    报表部署安装说明
    kafka单机安装测试-原创-本机测试过
    centos安装nginx 带upstream
    spring boot jpa mysql porm文件备份 可以运行的
    Spring boot jpa mysql 连接数据库SSL错误
    mysql 学习笔记
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10895941.html
Copyright © 2020-2023  润新知