zoukankan      html  css  js  c++  java
  • 折半搜索

    折半爆搜

    千篇一律

    基本数据范围在 (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
    ", 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
    ",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
    ",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('
    ');
    } 
    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
    ",ans);
    	return 0;
    }
    

    wait

  • 相关阅读:
    寻找字符串中只出现一次的第一个字符
    【二叉树】已知二叉树前序序列和中序序列,重建唯一二叉树
    单向链表插入与删除
    【二叉树->链表】二叉树结构转双向线性链表结构(先序遍历)
    先序构建二叉树及先序遍历二叉树
    【Leetcode】寻找数串中连续最大整数和且最大长度的子串
    稀疏矩阵存储、转置、乘法运算
    面试编程题拾遗(06) --- 打印n对括号的全部有效组合
    面试编程题拾遗(05) --- 括号匹配检查
    做到这一点,你也可以成为优秀的程序员
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13641103.html
Copyright © 2011-2022 走看看