解题报告:luogu P1356

题目链接: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;
}
原文地址:https://www.cnblogs.com/tlx-blog/p/12698046.html