题意:n个数中取若干个数,求sigma%m最大值为多少
思路:折半搜索+二分搜索[套路]
1.折半搜索,这题一共有35个数,很显然暴力不行.
2.先二进制暴力枚举一半,求出所有可能O(1e6),sum.
3.再二进制暴力枚举另一半,求出所有可能 sum1
4. sum1 <m && sum <m 求 max ((sum+sum1)%m)
5.
sum1+sum一共两种情况
一:2*m>=sum1+sum >=m 那么一定有sum越大越好
二:sum1+sum<=m 那么最大值存在于m-sum1-1
#include<bits/stdc++.h> #define PI acos(-1.0) using namespace std; typedef long long ll; const int N=1e5+50; const int MOD=1e9+7; const int INF=0x3f3f3f3f; ll a[50]; vector <ll> vec; int main(void){ ll n,m; cin >>n>>m; for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]%=m; ll nn=n/2; for(int i=0;i<=(1<<nn)-1;++i){ //二进制枚举状态 ll sum=0; for(int j=0;j<=20;j++){ int t=1&(i>>j); //位运算判断当前数加或者不加 if(t==1) sum+=a[j+1]; } sum%=m; vec.push_back(sum); } sort(vec.begin(),vec.end()); ll mx=-1; for(int i=0;i<=(1<<(n-nn))-1;++i){ ll sum=0; for(int j=0;j<=20;j++){ int t=1&(i>>j); if(t==1) sum+=a[j+nn+1]; } sum%=m; auto it=prev(lower_bound(vec.begin(),vec.end(),m-sum));//小技巧,寻找<=m-sum-1中最大的,即找到 第一个>=m-sum的数 的前一个数 mx=max(mx,*it+sum); mx=max(mx,(*vec.rbegin()+sum)%m); } cout << mx << endl; return 0; } /************** 10 1000 16140 63909 7177 99953 35627 40994 29288 7324 44476 36738 **************/