折半搜索

折半爆搜

千篇一律

基本数据范围在 \(n<=40\) 然后要搜索所有集合状态,

折半爆搜即搜前一半,再搜后一半(顺便统计答案)总复杂度由\(O(2^{40})\)降到 \(O(2^{20})\)

Incredible Cows

\(n\)数分成两堆,使得两堆和的差最小。

#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int N = 200005;
int T, n, a[2][N], m[2];
int h[N], f2[N], t[2], ans;
void dfs(int flag, int x, int y) {
	if (x > m[flag]) {
		if (flag) f2[t[flag]] = y; 
		else h[t[flag]] = y;
		t[flag]++;
		return;
	}
	dfs(flag, x + 1, abs(y + a[flag][x]));
	dfs(flag, x + 1, abs(y - a[flag][x]));
}
int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		t[0] = t[1] = 0;
		m[0] = (n + 1) / 2;
		m[1] = n / 2;
		for (int i = 1; i <= m[0]; i++) scanf("%d", &a[0][i]);
		for (int i = 1; i <= m[1]; i++) scanf("%d", &a[1][i]);
		dfs(0, 1, 0);
		dfs(1, 1, 0);
		sort(h, h + t[0]);
		sort(f2, f2 + t[1]);
		ans = 0x3f3f3f3f;
		for (int i = 0; i < t[0]; i++) {
			int k = lower_bound(f2, f2 + t[1], h[i]) - f2;
			if (k < t[1]) ans = min(ans, f2[k] - h[i]);
		}
		for (int i = 0; i < t[1]; i++) {
			int k = lower_bound(h, h + t[0], f2[i]) - h;
			if (k < t[0]) ans = min(ans, h[k] - f2[i]);
		}
		printf("%d\n", ans);
	}
	return 0;
}

世界冰球锦标赛

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long LL;
const int N=(1<<21);
inline LL read() {
	LL x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,mid;
LL m,a[2][45],l[N],r[N],t[2],ans;
void dfs(int f,int x,LL sum) {
	if(f&&x>n-mid) {
		r[++t[1]]=sum;
		return;
	}
	if(f==0&&x>mid) {
		l[++t[0]]=sum;
		return;
	}
	dfs(f,x+1,sum);
	dfs(f,x+1,sum+a[f][x]);
}
int main() {
	n=read();m=read();
	mid=(n+1)/2;
	for(int i=1;i<=mid;i++) a[0][i]=read();
	for(int i=1;i<=n-mid;i++) a[1][i]=read();
	dfs(0,1,0);
	dfs(1,1,0);
	sort(l+1,l+1+t[0]);
	sort(r+1,r+1+t[1]);
	for(int i=1;i<=t[0];i++) {
		int k=upper_bound(r+1,r+1+t[1],m-l[i])-r-1;
		ans+=k;
	}
	printf("%lld\n",ans);
	return 0;
}


9.7模拟赛T2

\([1,n]\)正着搜出来串存在\(Map\)里,然后\([n+1,2n]\)搜出来串反着连接从\(Map\)里找相同的贡献答案

#include <unordered_map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long LL;
int n;
char s[40];
LL ans;
unordered_map<string,int>mp;
bool vis[40];
void dfs1(int x) {
	if(x==n+1) {
		string s1,s2;
		for(int i=1;i<=n;i++) 
			if(vis[i]) s1+=s[i];
		for(int i=n;i>=1;i--) 
			if(!vis[i]) s2+=s[i];	
		mp[s1+'#'+s2]++;
		return;	
	}
	vis[x]=0;dfs1(x+1);
	vis[x]=1;dfs1(x+1);
}
void dfs2(int x) {
	if(x==2*n+1) {
		string s1,s2;
		for(int i=n+1;i<=2*n;i++) 
			if(vis[i]) s1+=s[i];
		for(int i=2*n;i>=n+1;i--) 
			if(!vis[i]) s2+=s[i];	
		ans+=mp[s2+'#'+s1]; 
		return;	
	}
	vis[x]=0;dfs2(x+1);
	vis[x]=1;dfs2(x+1);	
}
int main() {
	scanf("%d%s",&n,s+1);
	dfs1(1);
	dfs2(n+1);
	printf("%lld\n",ans/2);
	return 0;
}


11.9 模拟赛 hash_table

很类似上面

正着搜出来前一半串存在哈希表里,然后搜出来后一半从哈希表里找相反数贡献答案

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
const int N=7;
const int inf=2147483647;
inline int read() {
	int x=0,f=1;char ch=getchar();
	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;
}
void write(int x) {
	static short st[33];short tp=0;
	do st[++tp]=x%10,x/=10;while(x);
	while(tp) putchar('0'|st[tp--]);
	putchar('\n');
} 
int n,m;
int k[N],p[N],ans;
int Pow[155][7];
const int P=6974895;
struct Hash_Tale {
	int hd[P+5],to[P+5],nxt[P+5],tot,val[P+5];
	inline void ins(int x) {
		int v=(x%P+P)%P;
		for(int i=hd[v];i;i=nxt[i]) {
			if(to[i]==x) {
				++val[i];return;
			} 
		}
		to[++tot]=x;val[tot]=1;nxt[tot]=hd[v];hd[v]=tot;
	}
	inline int query(int x) {
		int v=(x%P+P)%P;
		for(int i=hd[v];i;i=nxt[i]) 
			if(to[i]==x) 	
				return val[i];
		return 0;
	}
}Hash;
void dfs1(int x,int sum) {
	if(x==(n/2)+1) {
		Hash.ins(sum);
		return;
	}
	for(int i=1;i<=m;i++)
		dfs1(x+1,sum+k[x]*Pow[i][p[x]]);
}
void dfs2(int x,int sum) {
	if(x==n+1) {
		ans+=Hash.query(sum);
		return;
	}
	for(int i=1;i<=m;i++)
		dfs2(x+1,sum-k[x]*Pow[i][p[x]]);
}
int main() {
	n=read();m=read(); 
	for(int i=1;i<=n;i++) {
		k[i]=read();p[i]=read();
	}
	for(int i=1;i<=m;i++)
		for(int j=0;j<=4;j++)
			Pow[i][j]=j?Pow[i][j-1]*i:1;
	dfs1(1,0);
	dfs2(n/2+1,0);
	write(ans);
	return 0;
}

CF888E Maximum Subsequence

给一个数列和\(m\),在数列任选若干个数,使得他们的和对\(m\)取模后最大\(1<=n<=35\)

#include <set>
#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;
const int N=40;
inline int read() {
	int x=0,f=1;char ch=getchar();
	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;
}
int n,m,a[N],mid;
set<int>st;
void dfs1(int x,int sum) {
	if(x==mid+1) {
		st.insert(sum);
		return;
	}
	dfs1(x+1,sum);
	dfs1(x+1,(sum+a[x])%m);
}

int ans;
void dfs2(int x,int sum) {
	if(x==n+1) {
		set<int>::iterator it=st.upper_bound(m-1-sum);
		it--; 
		ans=max(ans,sum+*it);
		return;
	}
	dfs2(x+1,sum);
	dfs2(x+1,(sum+a[x])%m);
}
int main() {
	n=read();m=read();
	mid=n/2;
	for(int i=1;i<=n;i++) a[i]=read();
	dfs1(1,0);
	dfs2(mid+1,0);
	printf("%d\n",ans);
	return 0;
}

wait

posted @ 2020-09-09 19:38  ke_xin  阅读(116)  评论(0编辑  收藏  举报