第三届NOI Online入门组第三题 手表(watch)题解

时间限制:1.0s
空间限制:256MB

题目描述

Jimmy到Symbol的手表店买手表,Jimmy 只带了 n n n种钱币,第 i i i种钱币的面额为 k k ki元,张数为 a a ai张。Symbol 的店里一共有 m m m块手表,第i块手表的价格为 t t ti元。
Symbol的手表店不能找零,所以Jimmy只能在凑出恰好的钱数时才能购买一块手表。现在对于店里的每块手表, Jimmy想知道他能不能凑出恰好的钱数进行购买。

输入格式

第一行两个空格分隔的整数 n n n m m m表示钱币数与手表数。
接下来n行每行两个空格分隔的整数 k k ki a a ai表示钱币的面额和张数。
n + 2 n+2 n+2行,共m个用空格分隔的整数 t t t i i i,表示每块手表的价格。

输出格式

一共 m m m行,对于第 i i i行,如果能凑出恰好的钱数购买第 i i i块手表则输出"Yes" (不含引号,下同),否则输出"No",注意只有首字母大写。

样例1输入

3 5
1 2
5 1
6 3
3 19 21 1 7

样例1输出

No
Yes
No
Yes
Yes

样例1解释

第二块手表 19 = 6 ∗ 3 + 1 = 6 ∗ 2 + 5 + 1 ∗ 2 19=6*3+1= 6*2+5+1*2 19=63+1=62+5+12,可以恰好凑出。
第四块手表 1 = 1 ∗ 1 1= 1*1 1=11,可以恰好凑出。
第五块手表 7 = 5 + 2 ∗ 1 = 6 ∗ 1 + 1 7=5+2*1=6*1+ 1 7=5+21=61+1,可以恰好凑出。

数据范围与提示

对于 50 50 50%的数据, n ≤ 10 n≤10 n10, m ≤ 60 m≤60 m60, a a ai ≤ 20 ≤20 20, k k ki ≤ 5000 ≤5000 5000, t t t i ≤ 250 ≤250 250
对于 100 100 100%的数据, 1 ≤ n ≤ 200 , 1 ≤ m ≤ 105 , 1 ≤ 1≤n≤200, 1≤m≤105, 1≤ 1n200,1m105,1 a a ai ≤ 1000 ≤1000 1000, 1 ≤ 1≤ 1 k k ki ≤ 500000 ≤500000 500000, 0 ≤ 0≤ 0 t t ti < 500000 < 500000 <500000

本人在考试的时候脑子抽筋了,导致最后dp超时,赛后发现可以通过二进制状态压缩dp卡数据

代码:

#include<bits/stdc++.h>
#define maxn 205
#define ll long long
using namespace std;
int n,m,x,cnt;
ll k[maxn],a[maxn],v[maxn*20],dp[500005];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    	cin>>k[i]>>a[i];
        for(int j=1;j<=a[i];j<<=1){
            v[++cnt]=j*k[i];
            a[i]-=j;
        }
        if(a[i])v[++cnt]=a[i]*k[i];
    }
    dp[0]=0;
    for(int i=1;i<=cnt;i++){
        for(int j=500000;j>=v[i];j--){
            dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
        }
    }
    while(m--){
        cin>>x;
        if(dp[x]==x)cout<<"Yes
";
        else cout<<"No
";
    }
	return 0;
}
她透过我的血,看到了另一抹殷红
原文地址:https://www.cnblogs.com/zhangbeini/p/13771264.html