zoukankan      html  css  js  c++  java
  • HDU 6865 Kidnapper's Matching Problem 的一些作题心得

    题意就不赘述。
    此题中两个元素(x,y)相等的充分必要条件是(x,y)对于某个线性基等价。
    等价即为从线性基中选出若干个元素异或上(x)后等于(y)
    那么第一种思考就是网上的常见做法
    借鉴大佬的博客
    将一个等价集合变成他的代表元素,这个代表元素即为该集合中所有元素异或上线性基中对应存在位的值得到的。
    那么为什么代表元素只有一个呢?
    考虑反证法
    假设(c eq d)
    考虑(a,b in S) (S)代表等价集合。
    考虑(a igoplus some elements in L = c)
    同理(b igoplus some elements in L = d)
    那么可推出(c igoplus some elements in L = d)
    但是(L)中的元素最高位(1)最高的那个(1)一定不会被去掉,所以选的集合只能为空集。
    那么(c = d)与假设矛盾
    附上代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=30;
    const int LEN=200010;
    const int M=1e9+7;
    int t,n,m,k,a[LEN],b[LEN],ne[LEN];
    struct linearbase{
    	int val[N];
    	void insert(int x){
    		for (int i=N-1; i>=0&&x; --i)
    		if ((x>>i)&1){
    			if (!val[i]){
    				val[i]=x;
    				break;
    			}
    			x^=val[i];
    		}
    	}
    	int check(int x){
    		for (int i=N-1; i>=0; --i)
    		if ((x>>i)&1) x^=val[i];
    		return x;
    	}
    	void clear(){
    		for (int i=0; i<N; ++i) val[i]=0;
    	}
    }L;
    int fp(int x,int y){
    	int ret=1;
    	for (; y; y>>=1,x=(ll)x*x%M) if (y&1) ret=(ll)ret*x%M;
    	return ret; 
    }
    void getnext(){
    	for (int i=2,j=0; i<=m; ++i){
    		while (j&&b[i]!=b[j+1]) j=ne[j];
    		if (b[i]==b[j+1]) ne[i]=++j; else ne[i]=0;//clear
    	}
    }
    int KMP(){
    	int ret=0;
    	getnext();
    	for (int i=1,j=0; i<=n; ++i){
    		while (j&&a[i]!=b[j+1]) j=ne[j];
    		if ((a[i]==b[j+1])&&(++j==m)){
    			(ret+=fp(2,i-m))%=M;
    			j=ne[j];
    		}
    	}
    	return ret;
    }
    int main(){
    	scanf("%d",&t);
    	while (t--){
    		L.clear();
    		scanf("%d%d%d",&n,&m,&k);
    		for (int i=1; i<=n; ++i) scanf("%d",&a[i]);
    		for (int i=1; i<=m; ++i) scanf("%d",&b[i]);
    		for (int i=1,x; i<=k; ++i){
    			scanf("%d",&x);
    			L.insert(x);
    		}
    		for (int i=1; i<=n; ++i) a[i]=L.check(a[i]);
    		for (int i=1; i<=m; ++i) b[i]=L.check(b[i]);
    		cout<<KMP()<<'
    ';
    	}
    }
    

    第二种考虑来自石昕怡学姐,如果(x igoplus y)的值对于线性基来说与零等价,那么(x)等价于(y)
    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=30;
    const int LEN=200010;
    const int M=1e9+7;
    int t,n,m,k,a[LEN],b[LEN],ne[LEN];
    struct linearbase{
    	int val[N];
    	void insert(int x){
    		for (int i=N-1; i>=0&&x; --i)
    		if ((x>>i)&1){
    			if (!val[i]){
    				val[i]=x;
    				break;
    			}
    			x^=val[i];
    		}
    	}
    	int check(int x){
    		for (int i=N-1; i>=0; --i)
    		if ((x>>i)&1) x^=val[i];
    		return x;
    	}
    	void clear(){
    		for (int i=0; i<N; ++i) val[i]=0;
    	}
    }L;
    int fp(int x,int y){
    	int ret=1;
    	for (; y; y>>=1,x=(ll)x*x%M) if (y&1) ret=(ll)ret*x%M;
    	return ret; 
    }
    void getnext(){
    	for (int i=2,j=0; i<=m; ++i){
    		while (j&&L.check(b[i]^b[j+1])) j=ne[j];
    		if (L.check(b[i]^b[j+1])==0) ne[i]=++j; else ne[i]=0;//clear
    	}
    }
    int KMP(){
    	int ret=0;
    	getnext();
    	for (int i=1,j=0; i<=n; ++i){
    		while (j&&L.check(a[i]^b[j+1])) j=ne[j];
    		if (L.check(a[i]^b[j+1])==0&&(++j==m)){
    			(ret+=fp(2,i-m))%=M;
    			j=ne[j];
    		}
    	}
    	return ret;
    }
    int main(){
    	scanf("%d",&t);
    	while (t--){
    		L.clear();
    		scanf("%d%d%d",&n,&m,&k);
    		for (int i=1; i<=n; ++i) scanf("%d",&a[i]);
    		for (int i=1; i<=m; ++i) scanf("%d",&b[i]);
    		for (int i=1,x; i<=k; ++i){
    			scanf("%d",&x);
    			L.insert(x);
    		}
    		cout<<KMP()<<'
    ';
    	}
    }
    
  • 相关阅读:
    luogu_P1850 换教室
    luogu_P3224 [HNOI2012]永无乡
    luogu_P1064 金明的预算方案
    luogu_P2014 选课
    luogu_P3372 【模板】线段树 1(动态开点)
    luogu_P2852 [USACO06DEC]牛奶模式Milk Patterns
    luogu_P1941 飞扬的小鸟
    luogu_P2678 跳石头
    luogu_P1638 逛画展
    【Tyvj2046】掷骰子
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/13662917.html
Copyright © 2011-2022 走看看