【题目】
【题意】
给定n个数进行加减运算,问是否能得到整除m的结果。
【思路】
因为题目涉及MOD运算,要想简化问题就需要知道一些基本的MOD运算性质:
A*B mod C=(A mod C*B mod C) mod C
(A+B) mod C=(A mod C+B mod C) mod C
有了这个性质,我们就可以把累加后求余转化成求余后累加(我们把减法看作加负数以后分析只说加法)再求余。
我们要判断的就是所有结果的累加和 mod K 是否为0。简记为:(A+B)mod K=0 or (A+B) mod K<>0 。
如果我们按数的个数划分阶段,前N-1个数的运算结果 MOD K看做A,第N个数看作B就OK了。
于是我们想到了这样的状态:dp[i,j]表示前i个数是否可以得到余数为j的结果。
那么状态转移方程就是
dp[ i,( j-a[i] mod k ) mod k ] = dp[ i-1, j ] (dp[ i-1,j ]=true);
dp[ i,( j+a[i] mod k) mod k ] = dp[ i-1, j ] (dp[ i-1,j ]=true);
如果dp[n,0]=true就输出‘Divisible’
好强啊!状态转移方程具有神奇的力量!我还是太菜了orz
【代码】
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <map>
#include <list>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <iostream>
#define go(i,a,b) for(int i=a;i<=b;i++)
#define og(i,a,b) for(int i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
using namespace std;
typedef long long ll;
bool dp[10005][105];
int a[10005];
main()
{
int t,n,k; scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
go(i,0,n-1)
{
scanf("%d",&a[i]);
a[i]=(a[i]%k+k)%k; //防止出现负数
}
mem(dp,0); dp[0][a[0]]=true;
go(i,1,n-1)
go(j,0,k-1)
if(dp[i-1][j])
dp[i][(j+a[i]+k)%k]=dp[i][(j-a[i]+k)%k]=true;
if(dp[n-1][0]) puts("Divisible");
else puts("Not divisible");
if(t) puts("");
}
}