枚举优化

Music Problem

http://www.nowcoder.com/questionTerminal/7d1948ec26b5429c82f3a4cf48784612

这道题感觉是枚举加一些优化在里面。
还是以例子为例吧。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");
    }

}
全部评论
比如你还在加某个数,你就把他把另外一个数的余数标记了,他很可能会和那个标记再次标记一次,比如dp[2]=1,你这次加1,然后把dp[3]加进去了,j变3的时候发现dp[3]=1,然后dp[4]=1,就这样停不下来了。
2 回复 分享
发布于 2020-04-14 23:47
#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])//如果发现了之前计算保留的值 { dp[(j+a[i])%3600] = 1; } } dp[a[i]%3600]=1; } if(dp[0]) printf("YES\n"); else printf("NO\n"); } } 这样写为啥会wa一样的啊
点赞 回复 分享
发布于 2020-04-14 23:39
因为你这样的话组合数会变多的
点赞 回复 分享
发布于 2020-04-14 23:45
一开始2000加入的时候,2000%3600=1600,便标记dp[1600]为1 为啥2000%3600 =1600 懵
点赞 回复 分享
发布于 2020-04-15 14:03
你好,我先更新dp[a[i]%3600]再去更新1-3600中间余数为什么会WA,但是先更新1-3600的余数最后更新dp[a[i]%3600]就过了?
点赞 回复 分享
发布于 2020-04-16 10:10
(1000+1600)%3600=1000和这个1000%3600=2600有点玄幻啊
点赞 回复 分享
发布于 2020-04-19 17:12

相关推荐

评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务