Link
SP30738 ADACOINS - Ada and Coins
Solve
看到题目很明显是一个背包(DP)用最常见的(DP)方法,定义(F[i][j])表示枚举到第(i)个时,是否能组成(j)这个状态,转移方程也比较显然了。
(F[i][j]|=F[i][j-a[i]])如果上一个状态(j-a[i])能组成的话,这个状态(j)也能组成。
但是i只代表阶段,可以把第一维去掉,为了防止重复,要倒过来刷,转移方程就变成了(F[j]|=F[j-a[i]])
考虑询问,(r)$l$区间看成$1$(r)(-)(1)~(l),所以只需要做一个前缀和减一下即可
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int N,F[maxn],S[maxn],A[maxn],Q;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int main(){
freopen("SP30738.in","r",stdin);
freopen("SP30738.out","w",stdout);
N=read();Q=read();
for(int i=1;i<=N;i++)A[i]=read();
F[0]=1;
for(int i=1;i<=N;i++)
for(int j=100000;j>=A[i];j--)F[j]|=F[j-A[i]];
S[0]=F[0];
for(int i=1;i<=100000;i++)S[i]=S[i-1]+F[i];
for(int i=1;i<=Q;i++){
int l=read(),r=read();
printf("%d
",S[r]-S[l-1]);
}
return 0;
}