判断整除(动态规划,递推)

总时间限制: 1000ms 内存限制: 65536kB
描述
一个给定的正整数序列,在每个数之前都插入+号或-号后计算它们的和。比如序列:1、2、4共有8种可能的序列:
(+1) + (+2) + (+4) = 7
(+1) + (+2) + (-4) = -1
(+1) + (-2) + (+4) = 3
(+1) + (-2) + (-4) = -5
(-1) + (+2) + (+4) = 5
(-1) + (+2) + (-4) = -3
(-1) + (-2) + (+4) = 1
(-1) + (-2) + (-4) = -7
所有结果中至少有一个可被整数k整除,我们则称此正整数序列可被k整除。例如上述序列可以被3、5、7整除,而不能被2、4、6、8……整除。注意:0、-3、-6、-9……都可以认为是3的倍数。

输入
输入的第一行包含两个数:N(2 < N < 10000)和k(2 < k< 100),其中N代表一共有N个数,k代表被除数。第二行给出序列中的N个整数,这些整数的取值范围都0到10000之间(可能重复)。
输出
如果此正整数序列可被k整除,则输出YES,否则输出NO。(注意:都是大写字母)
样例输入
3 2
1 2 4
样例输出
NO

//特别感谢//https://blog.csdn.net/keyword_/article/details/75303893?utm_source=blogxgwz5
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll f[10001][1001],a[10001];
/*
把数组定义在int main()外面,初始值为0
数组a用来待会存入输入数据
数组f是二元数组,从上往下代表一个个处理a[1],a[2]...
从左到右是和求余(取模)有关,下几行再讲
*/
int main()
{
///输入环节
    ll n,k;
    cin>>n>>k;
    for(ll i=1;i<=n;i++)
        cin>>a[i];

///处理环节
    f[1][a[1]%k]=1;
    /*
    首先f[1][...]的1表示正在处理a[1]这个数,
    然后这里用的是标记法:即符合某个条件就标记为1,
    所以那个1无计算意义,相当于true,不要纠结它,
    然后a[1]%k就是a[1]的模啦,
    所以f数组的意义也就明了了.
    之所以要定为二元数组而不是一元数组,
    就是为了从左到右找到一个横轴下标为a[i]的模,
    然后标记为1,
    那为什么f数组创建时横轴下标上限为1001而不是无限呢?
    因为k有范围,而横轴是存模的,
    一个数%k的取值范围在0到k-1之间,不可能超过k
    */
    for(ll i=2;i<=n;i++)//纵轴从2到n,因为第一个的模已经标记了,所以从2开始
        for(ll j=0;j<k;j++)//横轴j从0到k-1,因为模不可能超过k
            //两个for循环遍历f数组,即考虑全部可能
            /*
            如果f[i][j]=1,意义则是前i个数总和再去%k的值为j
            记住这个1意义只是标记而已
            j是模,如果j被标记为1则说明这个模是成立的,是对的
            */
            if(f[i-1][j])
            {
                /*
                如果前i-1个数总和再%k是j的话
                (j-a[i])%k是前i个数的模
                (j+a[i])%k也是前i个数的模,统统标记为1
                这里分类考虑是因为题目说明了正负情况都要考虑
                {如果不能理解(a[1]+a[2]+...+a[i])%k==((a[1]+a[2]+...+a[i-1])%k+a[i])%k
                请学习(同余定理)}
                */
                f[i][((j-a[i])%k+k)%k]=1;
                f[i][((j+a[i])%k+k)%k]=1;
                /*
                那为什么代码写那么复杂,((j-a[i])%k+k)%k,要%那么多次???
                那是因为j-a[i]可能%k是负数,但是这个数+k肯定大于0
                然后再%k就是正数了
                假如不这么做,并且j-a[i]是负数
                他若是直接%k得到的也是个负模,那数组下标j就撑不住负数了
                */
            }
///输出环节
    if(f[n][0]) cout<<"yes"<<endl;//0号位为1即模为0
    else cout<<"no"<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/zyacmer/p/9887215.html

时间: 2024-10-06 10:42:59

判断整除(动态规划,递推)的相关文章

山区建小学(区间型动态规划,递推)

描述政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 ).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值.输入第1行为m和n,其间用空格间隔第2行为(m-1) 个整数,依次

数的计数(noip2001,动态规划递推)

题目链接: 普通版: https://www.luogu.org/problemnew/show/P1028 数据加强版: https://www.luogu.org/problemnew/show/P2240 中间插一段,奇怪了,我明明想到的是最好的那种递推方法,结果写着写着忘记了,写成最差的递推方法 所以中间插一段被我遗忘的好方法 这个也是这题的书上的答案 #include<bits/stdc++.h> using namespace std; int a[1001]; int main(

[题解][SHOI2013]超级跳马 动态规划/递推式/矩阵快速幂优化

这道题... 让我见识了纪中的强大 这道题是来纪中第二天(7.2)做的,这么晚写题解是因为 我去学矩阵乘法啦啦啦啦啦对矩阵乘法一窍不通的童鞋戳链接啦 层层递推会TLE,正解矩阵快速幂 首先题意就是给你一个 n 行m 列 的格子图 一只马从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行. 题意很简单暴力dp的思路也很简单但是数据很恶心虽然远古一点,但毕竟是省选题 1 ≤ n ≤ 50,2 ≤ m ≤ 10^9 不过还是给了我们一点提示:n这么小? 总之我们先找出转移式对于每一个点

Prob.2[动态规划+递推+划归思想的应用]POJ 1958 Strange Towers Of Hanoi Upd:2020.3.1

传送门:http://poj.org/problem?id=1958 汉诺塔:https://www.cnblogs.com/antineutrino/p/3334540.html 问题引入:这个在标准的三塔问题上又加了一维,我们先考虑三个塔是怎么计算的?可以具体地分成三个步骤: 1.假设A塔上有n个盘子,将A塔上n-1个盘子转移到B塔上. 2.将A塔上剩余的一个盘子转移到C塔上. 3.将B塔上剩余的n-1个盘子转移到C塔上 因为后转移的盘子小,上面n-1个盘子都能落在上面,2之后的C柱可以看成

【动态规划/递推】BZOJ1806[IOI2007]- Miners

[思路] 用1.2.3分别代替三种食物,0表示当前矿井没有食物.f[i][a][b][c][d]当前第i个食物,矿1的食物顺序由上至下为a,b:矿2的食物顺序由上至下为c,d. 判断产物数量的方法很巧妙,由下至上a,b,c.初始时默认投入一个食物至少生产一单位,如果a为有食物且与bc不同,则加一单位:如果b为有食物且与c不同,再加一个单位.最后加一个滚动数组就可以了. [错因] 1.因为a,b,c,d大小范围是0..3,但是我把下标范围写3!一定要写4!我就是一不小心写错了,居然改了两个晚上,完

[P1192]台阶问题 - 动态规划 - 递推

https://www.luogu.org/problemnew/show/P1192 题目描述 有N级的台阶,你一开始在底部,每次可以向上迈最多K级台阶(最少1级),问到达第N级台阶有多少种不同方式. 输入输出格式 输入格式: 输入文件的仅包含两个正整数N,K. 输出格式: 输入文件stair.out仅包括1个正整数,为不同方式数,由于答案可能很大,你需要输出mod 100003后的结果. 输入输出样例 输入样例#1:复制 5 2 输出样例#1:复制 8 说明 对于20%的数据,有N ≤ 10

动态规划&mdash;&mdash;数字三角形(递归or递推or记忆化搜索)

动态规划的核心就是状态和状态转移方程. 对于该题,需要用抽象的方法思考,把当前的位置(i,j)看成一个状态,然后定义状态的指标函数d(i,j)为从格子出发时能得到的最大和(包括格子本身的值). 在这个状态定义下,原问题的解就是d(i,j). 下面看一下不同状态之间如何转移.从格子(i,j)出发有两种策略.如果向左走,则到(i+1,j)后需要求"从(i+1,j)出发能得到的最大和"这一问题,即d(i+1,j). 类似的,往右走之后需要求解d(i+1,j+1).由于可以在这两个决策中自由选

动态规划 数字三角形(递归,递推,记忆化搜索)

题目要求: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 在上面的数字三角形中寻找在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大.路径上的每一步都只能往左下或右下走.只需要求出这个最大和即可,不必给出具体路径. 三角形的行数大于1小于等于100,数字为 0 - 99 输入格式: 5 //三角形行数.下面是三角形 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 解题思路: 用二维数组存放数字三角形 D[r][j] //表示第i行第j个元素的

算法之动态规划(递推求解一)

这篇博客主要讲的是动态规划入门,即动态规划的思想,并且再讲解动态规划的最简单的一个方法. 首先,什么是动态规划? 动态规划是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决.其实就是分解问题,分而治之.可能这样说大家都不太理解,其实这个有点类似于数学中的递推公式.来举一个简单的例子,看下边这个题: N阶楼梯上楼问题:一次可以走两阶或一阶,问有多少种上楼方式. 这就是动态规划就简单的一个列子.拿到这个题,大家是不是都有点迷,这个到底怎么做?是不是没有思路,那