ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【每日一题】codeforces 577B(1900)(抽屉原理 and DP)

2020-05-23 20:04:32  阅读:266  来源: 互联网

标签:false int 577B codeforces 整除 抽屉 DP


每日一题,坚持使我强大


今日份快乐:codeforces 577B 传送门
明天份快乐:codeforces 1348D 传送门 (感觉给自己挖了个坑)


题目大意:

给 n 个数,问是否能找到一个子序列使得他们的和可以被 m 整除

分析

如果这是一个数据规模比较小的题,直接 DP 就可以过。我们可以利用抽屉原理来消减数据范围。

抽屉原理:如果 5 个抽屉放 6 个东西,那么肯定最少要有一个抽屉放两个或更多的东西
抽屉原理在取模计算的时候有很大的意义,给个实例来理解一下
eg: n = 7, m = 7

i 1 2 3 4 5 6 7
ai 12 8 6 17 20 34 36
sumi 12 20 36 53 73 107 143
sumi % 5 5 6 1 4 3 2 3

很明显 ( sum7 - sum 5 ) % 7 = 0,也就是说 (a6 + a7) % 7 = 0
这里的数据没有被 7 整除的数据,也就是说是,取余过后是七个数放在六个抽屉,最少要有两个前缀和的余数相同。
当然如果上例中出现可以被整除时,就是七个数放在七个抽屉里,虽然没余数相同的数,但是有直接满足要求的数

由上,我们就可以得出结论,当 n \geq≥ m 时,一定存在一个序列使得他们的和被 m 整除
我们再来看当 n < m 时,因为 m \leq≤ 1e3,,我们可以直接DP来求解

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 5;
int a[maxn] = {0};
bool dp[1005][1005] = {false};

int main() {

	ios::sync_with_stdio(false);
	
	int n, m;
	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		a[i] %= m;
	}
	
	bool ok = false;
	if(n >= m) ok = true, n = 0;  // 这里让 n = 0,下边的循环就不会执行
	
	for(int i = 1; i <= n; i++){
		dp[i][a[i]] = true;       	// 初始化
		for(int j = 0; j < m; j++){
			if(dp[i-1][j]) dp[i][j] = true;                 // 传递上一位的状态
			if(dp[i][j]) dp[i+1][(j + a[i+1]) % m] = true;  // 状态转移
		}
	}
	if(dp[n][0]) ok = true;   // 判断答案
	
	if(ok) cout << "YES" << endl;
	else cout << "NO" << endl;
	
    return 0;
}

坚持的时候很狼狈,等成功以后,丑的还是丑的

标签:false,int,577B,codeforces,整除,抽屉,DP
来源: https://blog.csdn.net/mldl_/article/details/106276832

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有