题解:P5997

共 309 字
1 分钟

提供一种全新的做法,时空均优于目前的其他做法,码量也很小。最优解被打表抢了,好难受。

由于 $\log 10^8 < 27,\log 24 < 5$,因此可以用一个 unsigned int 把其他题解里两个数据拼起来,同时排序也自带第一二关键字,最重要的是空间仅为正常做法的一半。

而且由于两个数据是关联的,内存连续性能让其速度更进一步,不必写结构体。

提交记录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<bits/stdc++.h>
using namespace std;
typedef unsigned int uint;
constexpr uint INF=0xffffffff;
int a[25],c[105];
uint dp[1<<24];
void out(){
	puts("NIE");
	exit(0); 
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	long long suma=0;
	for(int i=0;i<n;i++){
		scanf("%d",a+i);
		suma+=a[i];
	}
	for(int i=0;i<m;i++)scanf("%d",c+i);
	sort(c,c+m,greater<int>());
	int actualm=min(n,m);
	long long sumc=0;
	for(int i=0;i<actualm;i++)sumc+=c[i];
	if(suma>sumc)out();
	for(int i=0;i<n;i++)if(a[i]>c[0])out();
	for(int i=1;i<(1<<n);i++)dp[i]=INF;
	dp[0]=0;
	for(uint mask=0;mask<(1u<<n);mask++){
		uint val=dp[mask];
		if(val==INF)continue;
		uint b=val>>27;
		uint w=val&0x7ffffff;
		uint cb=c[b];
		uint unvis=((1u<<n)-1)^mask;
		while(unvis>0){
			int i=__builtin_ctz(unvis);
			unvis&=unvis-1;
			uint nw=w+a[i];
			if(nw<=cb){
				uint nval=(b<<27)|nw;
				uint nxtmask=mask|(1u<<i);
				if(nval<dp[nxtmask]){
					dp[nxtmask]=nval;
				}
			}else{
				uint nb=b+1;
				uint nw2=a[i];
				if(nb<(uint)actualm&&nw2<=(uint)c[nb]){
					uint nval=(nb<<27)|nw2;
					uint nxtmask=mask|(1u<<i);
					if(nval<dp[nxtmask]){
						dp[nxtmask]=nval;
					}
				}
			}
		}
	}
	if(dp[(1<<n)-1]==INF){
		out();
	}
	printf("%d",(dp[(1<<n)-1]>>27)+1);
	return 0;
}
Licensed under CC BY-NC-SA 4.0