hrbust 1445 Serial Numbers【01背包+滚动数组实现】

一场吉他寻回挑战赛中,吉他手需要通过串号找到属于自己的吉他。每把吉他都有一个唯一的串号,吉他手仅记得所有吉他串号之和为某个数M的倍数。本篇介绍了一种算法解决方案,通过动态规划找出最大数量的吉他,使得这些吉他的串号总和为M的倍数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Serial Numbers
Time Limit: 5000 MSMemory Limit: 65536 K
Total Submit: 13(7 users)Total Accepted: 12(7 users)Rating: Special Judge: No
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]);
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值