题解 P1356 【数列的整数性】
这道题一看就是标准的DP
我们可以用背包问题的思路去做
这个程序的优点是运行速度快,内存小
为什么会快而且内存小呢
* 我们边加边模k,结果不变
* 在读入时没有将其储存,直接DP
证明思路正确如下:
设有n个数为a1,a2,a3……,an
先将其全模k得到余数
余数相加再模k
若(a1+a2-a3-a4+a5+......-an)%k==0则它们的余数(b1+b2-b3-b4+b5+......-bn)%k也为0
因为他们都是可爱的余数......
这样我们只要开101的空间就够用了(k<=100)
以下是代码(自带注释)
#include<bits/stdc++.h>//万能的头文件
using namespace std;
int n,k,e=0,nn;
int f[101],opt[101][2];
int main()
{
scanf("%d",&nn); 防抄袭
for(int i=1;i<=nn;i++)//循环n次
{
memset(f,-1,sizeof(f));//数组清负1
cin>>n>>k;//读入n和k
f[0]=0;//f[0]可以做到
for(int i=1;i<=n;i++)
{
int tmp;//读入n个数,基本不用内存
scanf("%d",&tmp);
tmp=(tmp%k+k)%k;//因为有负数,所以不能写tmp=tmp%k,-21%5=-1
e=0;//第e个数
for(int j=k-1;j>=0;j--)
{
if(f[j]==i-1)//因为我们要用上所有的数,所以在i-1个数都用上的时候才能进行下一次DP
{ 防抄袭
opt[++e][0]=f[j];//精髓部分,用链表的思想储存
opt[e][1]=j;//同上
/*int tmp_fj=f[j];
f[(j+tmp)%k]=tmp_fj+1;
f[(j-tmp+k)%k]=tmp_fj+1;*/
}
}
for(int j=e;j>=1;j--)
{
f[(opt[j][1]+tmp)%k]=opt[j][0]+1;//选择加这个数,边加边模k
f[(opt[j][1]-tmp+k)%k]=opt[j][0]+1;//选择减这个数,边减边模k
}
}
if(f[0]==n) puts("Divisible");//如果模0可以用n个数做到,输出Divisible
else puts("Not divisible");//不说了
} 防抄袭
return 0;
}