……

解题报告:luogu P1356

题目链接:P1356 数列的整除性
lhr大佬问我一道题:
数字三角形那个题,求得分个位数的最大值。
然后我竟然秒了。
这个题其实也是一样的。
我们容易想到用\(dp[i][j]\)表示前\(i\)个数\(\bmod k\)\(j\)的方案有无。
很显然:

\[dp[i][j\pm a[i]\bmod 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][j][k]\)代表第\(i\)行第\(j\)列,个位数为\(k\)的方案。
后来考虑到可以状压,去掉\(k\)那一维。
这个题我们就有了空间\(\mathcal O(n\sqrt{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\n");
		else printf("Not divisible\n");
	}
	return 0;
}
posted @ 2020-04-14 14:55  童话镇里的星河  阅读(110)  评论(0编辑  收藏  举报