第五届华中区程序设计邀请赛暨武汉大学第十四届校赛 Problem 1608 - Calculation

本文深入探讨了AI算法在大数据开发领域的整合应用,详细介绍了如何利用AI技术提升数据处理效率,实现智能分析和预测。主要内容包括AI音视频处理、大数据开发、自然语言处理等关键技术的应用案例。

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




链接:戳这里


Problem 1608 - Calculation
Time Limit: 500MS   Memory Limit: 65536KB   
Description
Today, Alice got her math homework again!
She had n integers, and she needed to divide them into several piles or one pile. For each pile, if the teacher could get S, by + or – operator, then Alice got 1 small red flower. Alice wanted to get as many flowers as possible. Could you help her? Just tell her the maximum number of flowers she could get.
Input
The input consists of several test cases.
The first line consists of one integer T (T <= 100), meaning the number of test cases.
The first line of each test cases consists of two integer n (n<=14), meaning the number of the integer, and S (0<= S<= 100000000), meaning the result which teacher wanted.
The next line consists of n integer a1, a2, …, an (0<= ai <= 10000000).
You should know a few cases that n is larger than 12.
Output
For each test case, output one line with one integer without any space.
Sample Input
2
5 5
1 2 3 4 5
5 5
1 2 3 8 8
Sample Output
3
2


题意:给你n个数ai(1<=i<=n),任意去组合这些数,分成k个集合,集合里面的ai可以做+-操作,问你最多可以组成多少个集合使得集合的sum=m


思路:第一次写状压,大概就是把这n个数弄成2进制,每个数取或不取分别代表二进制上是1或者0,然后一开始先给每个集合加数进去,对应的二进制上第i位为1的就加上a[i]

然后要处理+-操作的问题,因为一开始我们是加上a[i]这个数啊,所以如果这个数是减的话我们直接减去两倍的a[i]就是了

对于当前的集合S,对于它的子集S0  减去两倍可以等于m的话说明这个集合S是满足操作和为m的  标记这个集合为1

接下来还是枚举集合S的子集S0,如果当前的集合S0是可以使得和为m的话,则dp[S]的权值为对应的S-S0这个子集的权值+1   即dp[S]=max(dp[S],dp[S-S0]+1)

然后直接输出dp[(1<<n)-1]这个总集合内满足条件的个数


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int T,n;
ll m,a[55],s[32768];
int f[32768],dp[32768];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%lld",&n,&m);
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        for(int S=0;S<(1<<n);S++){
            s[S]=0;
            for(int i=0;i<n;i++){
                if(S & (1<<i) ) s[S]+=a[i];
            }
        }
        for(int S=1;S<(1<<n);S++){
            f[S]=0;
            for(int S0=S;S0;S0=S&(S0-1)){
                ll t=s[S]-2*s[S0];
                if(t==m || s[S]==m) {
                    f[S]=1;
                    break;
                }
            }
        }
        int ans=0;
        for(int S=1;S<(1<<n);S++){
            dp[S]=0;
            for(int S0=S;S0;S0=S&(S0-1)){
                if(f[S0]==1) dp[S]=max(dp[S],dp[S^S0]+1);
            }
        }
        cout<<dp[(1<<n)-1]<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值