题解 SP30738 【ADACOINS Link Solve Code

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;
}