zoukankan      html  css  js  c++  java
  • CF1433F Zero Remainder Sum

    写在前面

    思维难度不是很大的 DP,代码实现也很容易。

    状态设计模式很套路,转移也很好理解。

    算法思路

    (因为 (k) 是常用的循环变量,下文中将题面中的模数改为 (p)

    虽然要求的是模 (p) 结果为 (0) 的答案,显然这个结果受到选择的数的和可能受到模 (p) 任何余数的影响。因此不妨设计状态的时候想到用一维来表示答案模 (p) 的余数。

    加上这一维之后就是一个背包模板了。

    (f_{i, j, t, k}) 表示在第 (i) 行前 (j) 个数中选出 (t) 个数,且模 (p)(k) 的最大答案。

    那么显然有:

    [f_{i, j, t, k} = max{f_{i, j - 1, t, k}, f_{i, j - 1, t - 1, (k - a_{i, j})mod p} + a_{i, j}} ]

    当可能存在多个(或多组) (a_{i, j}) 可能将同一个答案更新的时候,取最大值即可。

    这样分别处理处每一行的答案之后,再设 (g_{i, j}) 表示在前 (i) 行中选择某些数使得其和模 (p) 的余数为 (j) 的最大答案。

    那么显然有:

    [g_{i, j} = max{g_{i - 1, (j - k)mod p} + f_{i, m, t, k}} ]

    Tips

    • 注意一些边界条件。

    • 处理的时候可能会出现不合法的状态,即在某一行内选出某些数,其和模 (p) 的余数根本不可能等于枚举的 (k) 的情况。这种处理方式归根到底还是因为它是从“选 (0) 个数的时候余数却不为 (0)”这个不合法状态转移来的。有个简单的处理方式,只需要将初值设为负无穷,然后将合法的初始状态(即选择数的个数和余数都为 (0))设为 (0) 就好了。

    Code

    • 代码中对于每一行分别处理了这一行的 (f) 数组,并紧接着更新 (g) 数组,因此将 (f) 数组删掉了一维。

    • 代码中还使用了滚动数组。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int Maxn = 75;
    
    namespace Read {
    	inline int read() {
    		int fh = 1, res = 0; char ch = getchar();
    		for(; !isdigit(ch); ch = getchar()) if(ch == '-') fh = -1;
    		for(; isdigit(ch); ch = getchar()) res = (res << 3) + (res << 1) + (ch ^ '0');
    		return fh * res;
    	}
    }
    using namespace Read;
    
    int n, m, p;
    
    int a[Maxn][Maxn];
    
    int f[2][Maxn][Maxn];
    int g[2][Maxn];
    
    int main() {
    	n = read(); m = read(); p = read();
    	for(register int i = 1; i <= n; ++i) {
    		for(register int j = 1; j <= m; ++j) {
    			a[i][j] = read();
    		}
    	}
    	memset(g, -0x3f, sizeof(g));
    	g[0][0] = 0;
    	for(register int i = 1; i <= n; ++i) {
    		memset(f, -0x3f, sizeof(f));
    		f[0][0][0] = 0;
    		for(register int j = 1; j <= m; ++j) {
    			f[j & 1][0][0] = 0;
    			for(register int t = 1; t <= min(j, m/2); ++t) {
    				for(register int k = 0; k < p; ++k) {
    					f[j & 1][t][k] = max(max(f[j & 1][t][k], f[j - 1 & 1][t][k]), f[j - 1 & 1][t - 1][(k - (a[i][j] % p) + p) % p] + a[i][j]);
    				}
    			}
    		}
    		for(register int j = 0; j < p; ++j) {
    			g[i & 1][j] = g[i - 1 & 1][j];
    			for(register int t = 0; t <= (m / 2); ++t) {
    				for(register int k = 0; k < p; ++k) {
    					g[i & 1][j] = max(g[i & 1][j], g[i - 1 & 1][(j - (f[m & 1][t][k] % p) + p) % p] + f[m & 1][t][k]);
    				}
    			}
    		}
    	}
    	printf("%d", g[n & 1][0]);
    	return 0;
    }
    
  • 相关阅读:
    学习Mybatis与mysql数据库的示例笔记
    SpringAOP学习笔记
    idea开发ssh(Spring+struts+Hibernate)实现对MySQL数据库的增删改查
    springmvc加vue实现前后端数据的跨域访问
    idea开发工具springmvc加vue.js实现MySQL数据库的查询操作
    利用idea开发工具实现ssh(spring+struts+hibernate)加vue.js前后台对数据库的查询
    appweb 7.0.2版本编译
    Unable to register the DLL/OCX: RegSvr32 failed with exit code 0x3 我的解决方法
    无法定位程序输入点 InitializeCriticalSectionEx 于动态链接库 Kernel32.dll 上 问题解决方法
    海思3516D + IMX291图像闪烁问题定位
  • 原文地址:https://www.cnblogs.com/zimujun/p/14006428.html
Copyright © 2011-2022 走看看