线性dp+背包思维 [USACO09MAR]Cow Frisbee Team S(洛谷 P2946)

[USACO09MAR]Cow Frisbee Team S

题目描述

After Farmer Don took up Frisbee, Farmer John wanted to join in the fun. He wants to form a Frisbee team from his N cows (1 <= N <= 2,000) conveniently numbered 1…N. The cows have been practicing flipping the discs around, and each cow i has a rating R_i (1 <= R_i <= 100,000) denoting her skill playing Frisbee. FJ can form a team by choosing one or more of his cows.

However, because FJ needs to be very selective when forming Frisbee teams, he has added an additional constraint. Since his favorite number is F (1 <= F <= 1,000), he will only accept a team if the sum of the ratings of each cow in the team is exactly divisible by F.

Help FJ find out how many different teams he can choose. Since this number can be very large, output the answer modulo 100,000,000.

Note: about 50% of the test data will have N <= 19.

农夫顿因开始玩飞盘之后,约翰也打算让奶牛们享受飞盘的乐趣.他要组建一只奶牛飞盘

队.他的N(1≤N≤2000)只奶牛,每只部有一个飞盘水准指数Ri(1≤Ri≤100000).约翰要选出1只或多于1只奶牛来参加他的飞盘队.由于约翰的幸运数字是F(1≤F≤1000),他希望所有奶牛的飞盘水准指数之和是幸运数字的倍数.

帮约翰算算一共有多少种组队方式.

输入格式

  • Line 1: Two space-separated integers: N and F

  • Lines 2…N+1: Line i+1 contains a single integer: R_i

输出格式

  • Line 1: A single integer representing the number of teams FJ can choose, modulo 100,000,000.

如果你背包只会套一维模板的话,这道题是无法体现背包思维的;

dp[i][j] 表示前 i 个数组成数字 j 的种类数;

明显转移方程为:

  1. 如果不取第 i 个,dp[i][j]+=dp[i-1][j]
  2. 如果取第 i 个,dp[i][j]+=dp[i-1][j-a[i]]

这不就是01背包的思想吗?

但是这题跟裸题还是有区别的,首先是取模问题,可以先把输入数字a[i]就进行取模,那么体积 j 的范围变成了 0到f-1;

一般如果是 1到f 的话,一般是初始化dp[0][0],然后 j 从0开始,但是这显然不行,必须事先就对所有 dp[i][a[i]] 进行初始化,并且不能初始化dp[0][0];

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=2010;
const int M=2000100;
const LL mod=1e8;
int a[N];
LL dp[N][N];
int main(){
	int n,f;
	cin>>n>>f;
	for(int i=1;i<=n;i++) cin>>a[i],a[i]%=f; 
	for(int i=1;i<=n;i++) dp[i][a[i]]=1;//必须先赋初值,所以dp[0][0]就不要了 
	for(int i=1;i<=n;i++){
		for(int j=0;j<f;j++){//这个相当于从1开始遍历,所以之前要赋初值 
			(dp[i][j]+=dp[i-1][j]+dp[i-1][(j-a[i]+f)%f])%=mod;
		}
	}
	cout<<dp[n][0]<<endl;
	return 0;
}
发布了264 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291254/article/details/105278398
今日推荐