这道题感觉是枚举加一些优化在里面。
还是以例子为例吧。dp[i]=1表示某种组合加起来除以3600的余数为i,一开始的时候dp[]数组全为0;当某个组合是3600的倍数的时候,dp[0]=1,这便是说明可以组合形成3600的倍数,便可以输出YES,否则输出NO。
假如:
2000 1000 3000
一开始2000加入的时候,2000%3600=2000,便标记dp[2000]为1
下次加入1000的时候遍历dp数组一遍,会发现dp[1600]为1,便在这个基础上加上a[i]再对3600取模(这里因为只要1600被标记了故v中只加入了(1000+1600)%3600=1000),结果存储在v数组中,最后再用将v数组中存储的放入dp数组中(dp[1000]=1),在标记(1000%3600=2600)dp[2600]=1;
这样我们可以发现会大大缩小枚举范围,比如很多组合加起来%3600都为4,在下一次加入时候,我们只要计算一次便可以得出结果是多少。

#include<bits/stdc++.h>
using namespace std;
int T,m,a[100005];//用于存储初始数据
int dp[3605];
int v[10000];暂存下余数
int main()
{

    scanf("%d",&T);
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=m&&!dp[0];i++)
        {
            int cnt=0;
            for(int j=1;j<3600;j++)
            {
                if(dp[j])//如果发现了之前计算保留的值
                {
                    v[cnt++]=(j+a[i])%3600;
                }
            }
            for(int j=0;j<cnt;j++)
            {
                dp[v[j]]=1;
            }
            dp[a[i]%3600]=1; 
        }
        if(dp[0]) printf("YES\n");
        else printf("NO\n");
    }

}