51Nod3049 挑选数字
Problem
给出n个正整数,从中挑选若干个,使得他们的和为m。如果存在多个,输出排序后字典序最小的一组。如果没有找到任何一组,输出"No Solution"。
Solution
如果n大于15,从16开始分成两部分,先枚举后一半可能出现的值,map记录,然后按顺序枚举前一半,如果能和某个值组成m就记录每个数,返回,再枚举后一半,找到具体的数字。
主要是dfs写的太烂了,交对看别人的才知道怎么写。
Code
#include<stdio.h>
#include<set>
#include<iostream>
#include<stack>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
typedef long long ll;
typedef long double ld;
typedef double db;
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int mod=1e9+7;
inline int mo(ll a,int p){
return a>=p?a%p:a;
}
inline int rd() {
int x = 0, f = 1;
char ch;
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return f * x;
}
inline ll gcd(ll x, ll y){
return y==0?x:gcd(y,x%y);
}
inline ll speed(ll a,ll b){
ll cur=a,anss=1;
while(b){
if(b&1) anss=anss*cur;
cur=cur*cur;
b>>=1;
}
return anss;
}
const int MAXN=1e5;
bool ipr[MAXN+20];
int cnt,pri[MAXN/5];
void prime(){//埃式筛法
int N=sqrt(MAXN)+0.5,mul;
memset(ipr,true,sizeof(ipr));
ipr[1]=false;
for(int i=2;i<=N;i++){
if(ipr[i]==true){
i==2?mul=1:mul=2;
for(int j=i*i;j<=MAXN;j+=i*mul){
ipr[j]=false;
}
}
}
for(int i=2;i<=MAXN;i++){
if(ipr[i]==true){
pri[++cnt]=i;
}
}
}
int n,m;
int a[50];
int ans[50],ct=0,al=0,mid;
bool fg=false;
map<int,int>mp;
int sss=15;
void dfs(int cur,int sum,int cou){
if(fg) return;
if(sum==m){
fg=true;
ct=cou;
return;
}
if(cur==n+1) return;
ans[cou+1]=a[cur];
if(sum+a[cur]<=m&&al-sum-a[cur]>=m-sum-a[cur]) dfs(cur+1,sum+a[cur],cou+1);
if(al-sum>=m-sum) dfs(cur+1,sum,cou);
}
void dfs1(int cur,int sum){
mp[sum]=1;
if(cur==n+1) return;
dfs1(cur+1,sum+a[cur]);
dfs1(cur+1,sum);
}
void dfs2(int cur,int sum,int cou){
if(fg) return;
if(mp[m-sum]){
fg=true;
mid=sum;
ct=cou;
return;
}
if(cur==sss+1) return;
ans[cou+1]=a[cur];
if(sum+a[cur]<=m&&al-sum-a[cur]>=m-sum-a[cur]) dfs2(cur+1,sum+a[cur],cou+1);
if(al-sum>=m-sum) dfs2(cur+1,sum,cou);
}
bool fg2=false;
void dfs3(int cur,int sum,int cou){
if(fg2) return;
if(sum==m){
fg2=true;
ct=cou;
return;
}
if(cur==n+1) return;
ans[cou+1]=a[cur];
if(sum+a[cur]<=m&&al-sum-a[cur]>=m-sum-a[cur]) dfs3(cur+1,sum+a[cur],cou+1);
if(al-sum>=m-sum) dfs3(cur+1,sum,cou);
}
int main(){
//io_opt;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
al+=a[i];
}
if(al<m){
printf("No Solution\n");
return 0;
}
sort(a+1,a+1+n);
if(n<=sss){
dfs(1,0,0);
}
else{
dfs1(sss+1,0);
dfs2(1,0,0);
//cout<<ct<<endl;
if(fg) dfs3(sss+1,mid,ct);
//cout<<ct<<endl;
}
if(fg){
for(int i=1;i<=ct;i++){
printf("%d ",ans[i]);
}
printf("\n");
}
else{
printf("No Solution\n");
}
return 0;
}