BZOJ5285: [Hnoi2018]尋寶遊戲

【傳送門:BZOJ5285


簡要題意:

  懶惰成性
php

  PS:and和or運算符在這道題裏面是相同優先級的spa


題解:

  顯然&1或者|0都是沒有意義的操做code

  咱們把運算符也當成01,&表示1,|表示0xml

  這樣子對於一個運算式,就能夠轉成一個01字符串了blog

  咱們能夠一列一列處理值排序

  若某一列的最終值爲1,則須要知足最後一個|1的位置出如今最後一個&0的位置後面字符串

  爲0,則須要知足最後一個&0的位置要出如今最後一個|1的位置後面get

  能夠發現,使結果爲1的運算串爲全部字典序小於當前位構成的01串的01串string

  那麼結果爲0的運算串就是除告終果爲1的運算串以外的01串it

  那麼咱們就能獲得每一列運算串的範圍

  而後咱們只要取出全部列構成的運算串的範圍的公共部分就好了

  由於若是直接將01串轉成數字太大了,因此若是要比較兩個01串的大小就要用基數排序來肯定順序,從而肯定大小


參考代碼:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
char st[5100];
LL pw[1100],Mod=1e9+7,to1[5100];
int Rank[5100],cnt[2],tt[5100];
int main()
{
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);
    pw[1]=1;
    for(int i=2;i<=n+1;i++) pw[i]=(pw[i-1]<<1)%Mod;
    for(int i=1;i<=m;i++) Rank[i]=i;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",st+1);
        cnt[0]=cnt[1]=0;
        for(int j=1;j<=m;j++)
        {
            to1[j]=(to1[j]+LL(st[j]-'0')*pw[i])%Mod;
            cnt[st[j]-'0']++;
        }
        cnt[1]+=cnt[0];
        for(int j=m;j>=1;j--) tt[cnt[st[Rank[j]]-'0']--]=Rank[j];
        for(int j=1;j<=m;j++) swap(tt[j],Rank[j]);
    }
    reverse(Rank+1,Rank+m+1);
    while(q--)
    {
        scanf("%s",st+1);
        int l=0,r=m+1;
        for(int i=m;i>=1;i--)
        {
            if(st[Rank[i]]=='1')
            {
                r=i;break;
            }
        }
        for(int i=1;i<=m;i++)
        {
            if(st[Rank[i]]=='0')
            {
                l=i;break;
            }
        }
        if(l==0) printf("%lld\n",to1[Rank[r]]);
        else if(r==m+1) printf("%lld\n",(pw[n+1]-to1[Rank[l]]+Mod)%Mod);
        else if(l>=r) printf("%lld\n",(to1[Rank[r]]-to1[Rank[l]]+Mod)%Mod);
        else printf("0\n");
    }
    return 0;
}
相關文章
相關標籤/搜索