dp:Music Problem

链接:登录—专业IT笔试面试备考平台_牛客网

题目大意:输入n,序列包含n个整数,问是否能够找到一个子序列的和为3600的整数倍

题目数据可以达到1e9,这是远超3600的,事实上我们也无需真的去开一个1e9的数组来存放这些数据,因为要求的只是能否使和成为3600的倍数,所以我们只需关注它们与3600的余数即可。

另外,当n>3600的时候,前3600个数的和就一定是3600的倍数,就一定可以,所以我们在这种情况下就无需判断了。

那么在n<3600时,具体要怎么操作呢?

我们可以建立一个bool型的dp数组,里面存放的是小于3600的所有正整数,它代表能否使和与3600的余数为i,那么,当dp【0】为1时,我们就可以说找到了。对于每次操作,外层遍历所有物品,内层遍历所有背包容量j,如果j的dp值为真,那么这时加上遍历到的物品的重量mas【i】,则

dp【(j+mas[i])%3600】=1;另外,dp[mas[i]%3600]也要等于1,考虑的就是现在只放一个mas【i】,因为它的重量可能就是3600的倍数,自然不能忽略。

另外,

for(int i=1;i<=n&&!dp[0];++i){
        int cnt=0;
		for(int j=1;j<3600;++j){
			if(dp[j]){
                v[cnt++]=(j+mas[i])%3600;
			}
		}
        for(int j=0;j<cnt;++j){
            dp[v[j]]=1;
        }
        dp[mas[i]%3600]=1;
	}

该操作内部进行了多次取模处理,我们最好在存入数据时就把它们都对3600取模,这样后面就不会重复这么多次操作,可以节省时间。

同时你也会注意到,在这里我并没有像上面说的那样直接做  dp【(j+mas[i])%3600】=1,而是用了一个v数组来暂时存放余数,然后在小循环外部再把对应的余数对应的dp值改为真。

在代码注释中解释:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll mas[100010];
int dp[3700];
int n,t;
int v[10000];
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n;
	for(int i=1;i<=n;++i){
		cin>>mas[i];
		//mas[i]%=3600;
	}
	if(n>3600){
		cout<<"YES"<<endl;
		continue;
	}
	memset(dp,0,sizeof dp);
	for(int i=1;i<=n&&!dp[0];++i){
        int cnt=0;
		for(int j=1;j<3600;++j){
			if(dp[j]){//比如你还在加某个数,你就把他把另外一个数的
                //余数标记了,他很可能会和那个标记再次标记一次,比如dp[2]=1,
                //你这次加1,然后把dp[3]加进去了,j变3的时候发现dp[3]=1
                //,然后dp[4]=1,就这样停不下来了。
                //问题出在判断上,后面的dp【j】也会等于0,就超时了?
	//dp[(j+mas[i])%3600]=1;
                v[cnt++]=(j+mas[i])%3600;
			}
		}
        for(int j=0;j<cnt;++j){
            dp[v[j]]=1;
        }
        dp[mas[i]%3600]=1;
	}
	if(dp[0]){
		cout<<"YES"<<endl;
	}
	else{
		cout<<"NO"<<endl;
	}
}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值