Serial Numbers | ||||||
| ||||||
Description | ||||||
The great guitar player Bernhard-Anton Peter Cobain is playing with his band the Awesome Crying Metalheads in the wonderful city of Leiden. The show goes well and Bernhard-Anton is very happy, but after the show he has a big problem: his guitars are mixed up with all the guitars of the other guitar players, and Bernhard-Anton does not remember which guitars were his. Fortunately, every guitar has a unique serial number which is an integer between 1 and 100, 000. The only thing that Bernhard-Anton remembers is that the sum of all the serial numbers of his guitars is a multiple of M. Given all serial numbers and the number M, calculate the maximum number of guitars that could have been Bernhard-Anton’s. | ||||||
Input | ||||||
The first line of the input contains a single number: the number of test cases to follow. Each test case has the following format: • One line with two integers N and M, satisfying 1 ≤ N ≤ 500 and 1 ≤ M ≤ 100, 000: the total number of guitars and the number M. • One line with N different integers S1 . . . SN satisfying 0 ≤ Si ≤ 100, 000: the serial numbers of the guitars. Integers on the same line are separated by single spaces, and there will always be at least one subset of guitars such that the sum of their serial numbers is a multiple of M. | ||||||
Output | ||||||
For every test case in the input, the output should contain a single number, on a single line: the maximum number of guitars such that the sum of their serial numbers is a multiple of M. | ||||||
Sample Input | ||||||
2 3 5 1 8 6 6 9 8 6 4 1 2 3 | ||||||
Sample Output | ||||||
3 5 | ||||||
Source | ||||||
Preliminaries BAPC 2010 |
题目大意:
给你N个数,求一个方案,使得其数字和为M的倍数,并且数字个数最多,求这个最多的个数。
思路:
1、考虑dp,设定dp【i】【j】表示dp到第i个数字的时候,和模为j的最多数字个数。
2、考虑状态转移方程,不难想到:
①对应一个数拿与不拿,而且如果拿只能拿一次,那么对应不难想到这个题就是一个01背包的变形。
②我们如果从上一状态转移到当前状态不是很好实现,因为有取模的操作,那么我们考虑将当前状态转移到下一状态
③dp【i+1】【j】=max(dp【i+1】【j】,dp【i】【j】);
表示我第i个数不拿的状态的转移方程。
④dp【i+1】【(j+a【i】)%m】=max(dp【i+1】【(j+a【i】)%m】,dp【i】【j】+1);
表示我第i个数拿取的状态的转移返程。
⑤对应注意一些实现细节以及初始化即可。
3、理工OJ很蛋疼,直接裸开的int dp【505】【100007】被卡了MLE、明显出题人就是想让我们用一维01包来写,但是宝宝就是任性,直接加个滚动数组即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int dp[3][100007];
int a[15151];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
dp[1][a[1]%m]=1;
for(int i=2;i<=n;i++)
{
dp[2][a[i]%m]=1;
for(int j=0;j<m;j++)
{
dp[2][j]=max(dp[1][j],dp[2][j]);
if(dp[1][j]>0)
{
dp[2][(j+a[i])%m]=max(dp[2][(j+a[i])%m],dp[1][j]+1);
}
}
for(int j=0;j<m;j++)
{
dp[1][j]=dp[2][j];
dp[2][j]=0;
}
}
printf("%d\n",dp[1][0]);
}
}