Loading

题解 lg2946 [USACO09MAR]Cow Frisbee Team S

题意

问从序列里面取出一些数,使数字的和为F的倍数的方案数

思路

明显我们可以用某种凑的方式来满足条件,这很容易想到01背包

不过是方案数诶,那我们的背包就是要来统计答案

\(f(i,j)\)表示考虑到第\(i\)个数字,此时和模F的值为\(j\),这样设状态就十分好转移

f(i,j)=f(i,j)+f(i-1,j)+f(i-1,((j-a[i])%F+F)%F)

注意f(i,a[i])也是一种方案,所以设为1

代码

#include<bits/stdc++.h>
using namespace std;
int const MAXN=2010,MOD=1e8;
int n,F;
int r[MAXN],f[2][MAXN];


int main(){
	scanf("%d%d",&n,&F);
	for(int i=1;i<=n;i++){
		scanf("%d",&r[i]);r[i]%=F;
	}
	int cur=0;
	f[0][r[1]]=1;
	for(int i=2;i<=n;i++){
		cur^=1;
		memset(f[cur],0,sizeof(f[cur]));
		f[cur][r[i]]=1;
		for(int j=0;j<=F-1;j++){
			f[cur][j]=(f[cur][j]+f[cur^1][j]+f[cur^1][((j-r[i])%F+F)%F])%MOD;
			//printf("%d ",f[cur][j%F]);
		}
		//printf("\n");
	}
	printf("%d\n",f[cur][0]);
	return 0;
}

思考

明显的,这道题的01背包状态和别的不太一样,但是核心还是01背包的方法.不能只抓住表象,还是要运用其本质

posted @ 2020-11-20 10:44  fpjo  阅读(66)  评论(0编辑  收藏  举报