zoukankan      html  css  js  c++  java
  • P7717-「EZEC-10」序列【Trie】

    正题

    题目链接:https://www.luogu.com.cn/problem/P7717


    题目大意

    求有多少个长度为(n)的序列(a)满足,都在([0,k])的范围内且满足(m)个限制刑如:(a_x xor a_y=z)

    (0leq n,mleq 5 imes 10^5,0leq k<2^{30})


    解题思路

    首先假设有合法方案,那么对于一个位置(a_x)确定之后与它直接或间接限制的(a_y)都将被确定。

    我们可以设限制为一条边,然后先(dfs)判断一次是否限制之间没有冲突。

    然后考虑对于每个联通块我们随意找到一个位置(x),那么其他的点都将被表达为(a_x xor w)的形式。

    然后我们要求找到有多少个(a_x)满足对于所有的(w)都有(a_x xor wleq k)

    这个可以用(Trie)数来做,每次封闭的是一个子树,直接处理就好了。

    时间复杂度(O(nlog k))


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #define ll long long
    using namespace std;
    const ll N=5e5+10,P=1e9+7;
    struct node{
    	ll to,next,w;
    }a[N<<1];
    ll n,m,k,tot,ls[N],z[N];
    ll cnt,t[N][2],res,ans=1;
    bool v[N];stack<ll > s;
    void addl(ll x,ll y,ll w){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	ls[x]=tot;a[tot].w=w;
    	return;
    }
    bool dfs(ll x){
    	v[x]=1;s.push(z[x]);
    	for(ll i=ls[x];i;i=a[i].next){
    		ll y=a[i].to;
    		if(v[y]){
    			if((z[x]^a[i].w)!=z[y])
    				return 1;
    		}
    		else{
    			z[y]=z[x]^a[i].w;
    			if(dfs(y))return 1;	
    		}
    	}
    	return 0;
    }
    void Limit(ll &x,ll w,ll p){
    	if(x==-1||p<0)return;
    	if(!x){x=++cnt;t[x][0]=t[x][1]=0;}
    	if((k>>p)&1)Limit(t[x][(w>>p)&1^1],w,p-1);
    	else{
    		t[x][(w>>p)&1^1]=-1;
    		Limit(t[x][(w>>p)&1],w,p-1);
    	}
    	return;
    }
    void Count(ll x,ll L,ll R){
    	if(L>k)return;
    	if(x==-1)res-=min(R,k)-L+1;
    	if(x<=0)return;
    	ll mid=(L+R)>>1;
    	Count(t[x][0],L,mid);
    	Count(t[x][1],mid+1,R);
    	return;
    }
    signed main()
    {
    	scanf("%lld%lld%lld",&n,&m,&k);
    	for(ll i=1;i<=m;i++){
    		ll x,y,w;
    		scanf("%lld%lld%lld",&x,&y,&w);
    		addl(x,y,w);addl(y,x,w);
    	}
    	res=0;
    	for(ll i=1;i<=n;i++){
    		if(v[i])continue;cnt=t[0][0]=0;
    		if(dfs(i))return puts("0")&0;
    		while(!s.empty())Limit(t[0][0],s.top(),29),s.pop();
    		res=k+1;Count(1,0,(1<<30)-1);
    		ans=ans*res%P;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    1月27日 常用函数
    1月25日 JavaScript的DOM操作
    1月25日 JavaScript简介与语法
    1月24日 样式表案例
    5月14日 数字顺序打印并求和
    5月14日 根据班级人数,求平局分,最大值,最小值
    5月14日 九九乘法口诀
    5月14日 打印100以内与7有关的数
    5月14日 函数练习 100以内奇数的和
    5月14日 枚举类型
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14999458.html
Copyright © 2011-2022 走看看