• 【BZOJ5285】【HNOI2018】—寻宝游戏(结论题)


    传送门

    题意:给你nn个有序0101串,你必须在每2个串中间加入&&或者|,多次询问有多少种方法能得到某一个的串

    思路妙♂妙的题啊

    分析一下&&|的性质
     0| 0->不变
     1| 1->必为1
    &0&0->必为0
    &1&1->不变

    考虑对于一个询问串qq和所有串的某一位
    如果qq某一位为00
    那么这一位最后必定有一个位置为00的地方运算符为&&
    而且这个&&之后必定没有1|1,即是00的地方为|,是11的地方为&&
    如果qq某一位为11
    那么这一位最后必定有一个位置为11的地方运算符为|
    而且这个|之后必定没有&0& 0,即是00的地方为|,是11的地方为&&
    有没有发现什么?
    并没有

    如果我们把|看做0‘0’11看做1‘1’
    那是不是在比较字典序了
    如果最后一位为00,那也就是说第一个&0& 0,即运算符字典序他大的方案
    最后一位为11同理,即运算符字典序比他小的方案

    那对于qq一位0/10/1来说,字典序/大/小于他的所有方案都合法
    那一个串的答案,就是所有合法方案的交集
    也就是qq最低为11的位置的答案和最高的一位为00的答案的差
    把所有串的同一位看做一个串排个序就可以愉快的解决了

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define int long long
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const ll mod=1e9+7;
    const int M=5005;
    int n,m,q;
    ll sum[M];
    char s[M],r[M];
    struct line{
    	int id;
    	char a[M];
    }p[M];
    inline bool comp(const line &a,const line &b){
    	for(int i=1;i<=n;i++){
    		int f1=a.a[i]-'0',f2=b.a[i]-'0';
    		if(f1==f2)continue;
    		return f1<f2;
    	}
    }
    inline ll calc(int x){
    	ll res=0;
    	for(int i=1;i<=n;i++){
    		res=res*2%mod;
    		if(p[x].a[i]=='1')res++;
    	}
    	return res;
    }
    inline ll ksm(ll a,int b,ll res=1){
    	for(;b;b>>=1,a=a*a%mod){
    		if(b&1)res=res*a%mod;
    	}
    	return res;
    }
    signed main(){
    	n=read(),m=read(),q=read();
    	ll mx=ksm(2,n);
    	for(int i=1;i<=n;i++){
    		scanf("%s",s+1);
    		for(int j=1;j<=m;j++){
    			p[j].a[n-i+1]=s[j];
    		}
    	}
    	for(int i=1;i<=m;i++)p[i].id=i;
    	sort(p+1,p+m+1,comp);
    	for(int i=1;i<=m;i++)
    		sum[i]=calc(i);
    	for(int i=1;i<=q;i++){
    		scanf("%s",s+1);
    		int pos1=0,pos2=0;
    		for(int j=1;j<=m;j++){
    			if(s[p[j].id]-'0'){
    				pos1=j;break;
    			}
    		}
    		for(int j=m;j;j--){
    			if(!(s[p[j].id]-'0')){
    				pos2=j;break;
    			}
    		}
    		if(pos1&&pos2&&pos2>pos1)puts("0");
    		else{
    			if(pos1)cout<<(sum[pos1]-sum[pos2]+mod)%mod;
    			else cout<<(mx-sum[pos2]+mod)%mod;
    			puts("");
    		}
    	}
    }
    
  • 相关阅读:
    【Python第九篇】异步IO数据库队列缓存
    【Python第八篇】线程、进程及协程
    【Python第七篇】Socket网络编程
    实验五全部代码,ajax请求
    添加员工
    联级选择
    查询,利用jquery选择器
    列表、表格单选框
    注册
    聊天框
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145637.html
Copyright © 2020-2023  润新知