POJ 1745 线性和差取余判断

POJ 1745 线性和差取余判断

题目大意:每个数都必须取到,相加或相减去,问所有的方案最后的得数中有没有一个方案可以整除k

这个题目的难点在于dp数组的安排上面

其实也就是手动模仿了一下

比如

一个数,不用说,第一个数之前不用加符号就是本身,那么本身直接对K取余,
那么取17的时候有个余数为2————基础
然后来了一个5,
(2 + 5)对7取余为0————层层延伸
(2 - 5)对7取余为4(将取余的负数变正)

那么前2个数有余数0和4
再来一个-21
(0+21)对7取余为0
(0-21)对7取余为0
(4+21)对7取余为4
(4-21)对7取余为4
再来一个-15同样是这样
(0+15)%7 = 1
(0-15)%7 = 6
(4+15)%7 = 5
(4-15)%7 = 3
同理可以找到规律,定义dp[i][j]为前i个数进来余数等于j是不是成立,1为成立,0为不成立

所以可以定义dp[i][j]如下:对于前i个数,得出的结果除以k的余数是否为j的0,1布尔值

所以层层递推后,只要看dp[n][0]就可以啦

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#define inf (1 << 30)
using namespace std;
const int maxn = 120;
const int maxm = 1e4 + 10;
int dp[maxm][maxn];
int a[maxm];
int posmod(int n,int k)
{
    n = n % k;
    while(n < 0)
    {
        n += k;
    }
    return n;
}
int main()
{
    int n,k;
    while(~scanf("%d%d",&n,&k))
    {
        for(int i = 1;i <= n;i++)
            scanf("%d",&a[i]);
//      dp[i][j]表示取到第i个数除以k的余数是不是j
        memset(dp,0,sizeof(0));
        dp[1][posmod(a[1],k)] = 1;

        for(int i = 2;i <= n;i++)
        {
            for(int j = 0;j < k;j++)
            {
                if(dp[i-1][j])//由一个已知的关系向上推
                {
                    dp[i][posmod(j+a[i],k)] = 1;
                    dp[i][posmod(j-a[i],k)] = 1;
                }
            }
        }
        if(dp[n][0])
        {
            cout<<"Divisible"<<endl;
        }
        else
        {
            cout<<"Not divisible"<<endl;
        }
    }
    return 0;
}

感觉这个题通了一点dp的窍~~嘿嘿嘿加油

原文地址:https://www.cnblogs.com/DF-yimeng/p/9372847.html