题目链接:P1356 数列的整除性
lhr大佬问我一道题:
数字三角形那个题,求得分个位数的最大值。
然后我竟然秒了。
这个题其实也是一样的。
我们容易想到用(dp[i][j])表示前(i)个数(mod k)为(j)的方案有无。
很显然:
[dp[i][jpm a[i]mod k]=dp[i-1][j]
]
我们要注意负数取模的处理:
inline int mod(int n,int p)
{
if(n>=0) return n%p;
int g=abs(n)/p;
return (n+g*p+p)%p;
}
然后直接递推就好了。
有序的(dp)果然简单。
时间复杂度是(mathcal O(Tnk)),然后就过了。
对于上面哪那一题,可以用(dp[i][ij][k])代表第(i)行第(j)列,个位数为(k)的方案。
后来考虑到可以状压,去掉(k)那一维。
这个题我们就有了空间(mathcal O(nsqrt{k}))的做法,即把得数化成(sqrt{k})进制,然后数组的值进行状压即可。
不过有些难打,就只写了无脑的做法。
(Code);
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define read(x) scanf("%d",&x)
int t,n,a[10005],k;
int dp[10005][105];
inline int mod(int n,int p)
{
if(n>=0) return n%p;
int g=abs(n)/p;
return (n+g*p+p)%p;
}
int main()
{
read(t);
while(t--)
{
memset(dp,0,sizeof(dp));
read(n),read(k);
for(int i=1;i<=n;i++) read(a[i]);
dp[1][mod(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][mod(j+a[i],k)]=1;
dp[i][mod(j-a[i],k)]=1;
}
}
}
if(dp[n][0]) printf("Divisible
");
else printf("Not divisible
");
}
return 0;
}