题目链接
解一:
由鸽巢原理,一个由n个数组成的数列 一定能找出若干个连续的数使它们之和能被n整除
所以直接剪枝,大于3600输出YES
f[i][j]
表示前i
个数余数为j
的个数
状态转移方程:
f[i][j]|=f[i-1][j]
f[i][(j+a[i])%3600]|=f[i-1][j]
#include <iostream>
#include <string.h>
using namespace std;
int a[100010];
int f[3610][3610];
void solve()
{
memset(f,0,sizeof f);
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
if(n>3600)
{
cout<<"YES"<<endl;
return ;
}
for(int i=1;i<=n;i++){
f[i][a[i]%3600]=1;
for(int j=0;j<3600;j++){
f[i][j]|=f[i-1][j];
f[i][(j+a[i])%3600]|=f[i-1][j];
}
}
if(f[n][0]==0){
cout<<"NO"<<endl;
}else cout<<"YES"<<endl;
}
int main()
{
int t;
cin>>t;
while(t--){
solve();
}
}
解二:二进制bitset+dp
bitset巧妙做法
每次状态转移
f|=(f<<a[i])|(f<<a[i]>>mod)
#include <bits/stdc++.h>
using namespace std;
const int mod = 3600;
int a[100010];
void solve()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
a[i]%=mod;
}
bitset<2*mod>f;
for(int i=1;i<=n;i++)
{
f|=(f<<a[i])|(f<<a[i]>>mod);
f[a[i]]=1;
}
if(f[0])cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
int main()
{
int t;
cin>>t;
while(t--){
solve();
}
}