有n件物品,每件物品有三个属性a[i], b[i], c[i] (a[i] 再给出q个询问,每个询问由非负整数m, k, s组成,问是否能够选出某些物品使得:
a , b , m , s < = 1 e 9 a,b,m,s <=1e9 a,b,m,s<=1e9
n , c < = 1 e 3 n,c<=1e3 n,c<=1e3
k < = 1 e 5 k<=1e5 k<=1e5
q < = 1 e 6 q<=1e6 q<=1e6
题解:
首先这个题的 a , b , q a,b,q a,b,q都很大,这启发我们绝对不能存这些东西(这些东西不是突破口)。
发现 k k k可以接受,我们做一个大小为 1 e 5 1e5 1e5的背包,做 n ( 1 e 3 ) n(1e3) n(1e3)次。
好卡啊
那么怎么满足 a , b a,b a,b的限制呢?
可以离线把询问从小到大排序,物品按 a a a从小到大排序。
那么可以在边插入的时候直接对整个背包中求 b b b满足条件的答案。
我们就把 a a a给解决了。
那么 b b b呢?
发现合法的方案,所有的 b > m + s b>m+s b>m+s,也就是最小的 b > m + s b>m+s b>m+s,那么背包的时候我们 f [ x ] f[x] f[x]表示大小为 x x x的所有方案中最小的 b b b的最大值,那么 f [ k ] > m + s f[k] > m+s f[k]>m+s就和有方案达成条件等价。
A C C o d e {AC\ Code} AC Code
#pragma GCC optimize(2)
#include
#define maxn 1005
#define pb push_back
using namespace std;
int n,q,c[maxn],a[maxn],b[maxn],d[maxn],f[100005],ans[1000005];
vector<int>l[maxn],K[maxn],id[maxn];
bool cmp(const int &u,const int &v){
return a[u] < a[v];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&c[i],&a[i],&b[i]);
d[i] = i;
}
sort(d+1,d+1+n,cmp);
scanf("%d",&q);
for(int i=1,m,k,s;i<=q;i++){
scanf("%d%d%d",&m,&k,&s);
a[0] = m;
int t = upper_bound(d+1,d+1+n,0,cmp)-d-1;
l[t].pb(m+s),K[t].pb(k),id[t].pb(i);
}
memset(f,-0x3f,sizeof f);
f[0] = 0x3f3f3f3f;
for(int i=1;i<=n;i++){
int u = d[i];
for(int j=100000;j>=c[u];j--)
f[j] = max(f[j] , min(f[j-c[u]],b[u]));
for(int j=0;j<l[i].size();j++)
ans[id[i][j]] = (f[K[i][j]] > l[i][j]);
}
for(int i=1;i<=q;i++)
puts(ans[i]?"TAK":"NIE");
}