Music Problem
题意:
分析:
最开始想到的是鸽巢原理,即当 \(n\geq 3600\) 时,必定存在一段连续的数之和为 \(3600\) 的倍数。但是当 \(n<3600\) 时,就不知道怎么处理了。
看了别人的代码,才发现是 \(dp\)。另外发现还有一种做法,借助 \(bitset\) 来枚举,判断哪些数是可以得到的,\(bt[i]\) 表示 \(i\) 可以得到。
对于当前枚举到的数 \(a[i]\),如果直接枚举其他数,来得到新的数,复杂度就会比较高。
这时,采用 \(bitset\),借助位移来直接处理。
\(bt<<a[i]\) 表示所有数同时加上 \(a[i]\) 所得到的数,但可能会溢出 \(3600\) 的范围,所以要用 \(bt>>(3600-a[i])\) 来表示,最后两者相或,统计结果,然后或到 \(bt\) 上。接着把 \(bt[a[i]]\) 赋 \(1\)。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=3605;
const int maxn=1e5+5;
bitset<N>bt;
int a[maxn];
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
bt.reset();
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]%=3600;
}
if(n>=3600)
printf("YES\n");
else
{
for(int i=1;i<=n;i++)
{
bt|=((bt<<a[i])|(bt>>(3600-a[i])));
bt[a[i]]=1;
}
if(bt[0])
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}