luogu P4424 [HNOI/AHOI2018]寻宝游戏
首先有一个显然的爆搜,因为太显然了所以在这里懒得讲。
我们发现后面的影响显然要更大一点,所以我们倒着搜这个运算符。
首先我们发现\(\and 1\)和\(\or 0\)对答案没有影响,所以这个可以只看成\(\and 0\)和\(\or 1\),我们称这样的操作是决定性的。如果一个决定性的操作的这一位后面没有任何决定性的操作,那么这个就是答案。
这里我们发现,如果每一位都是确定了,那么更前面的直接随便填就好了。容易证明每一层只有\(O(m)\)个不交的状态,所以总复杂度\(O(nmk)\),可以过70pts。
然后我就在这条路上越走越远了……
事实上做法和这个毫不相干……考虑将\(\or\)设为\(0\),\(\and\)设为\(1\),后面的数为高位,那么我们发现一个数出来的答案为\(1\)当且仅当其大于运算符的这个数。于是就变成一个求区间交的问题了,可以做到\(O(mk+\frac{nm\log m}{w})\)
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e3+5,M=5e3+5,K=2e3+5,mod=1e9+7,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,m,k,x,y,z,Id[M];ll Po[N],Ans;char s[M];
struct Ques{bitset<N> f;int Id;}S[M];bool cmp(Ques x,Ques y){int Pt=(x.f^y.f)._Find_first();if(Pt>n) return 1;return !x.f[Pt];}
ll calc(int p){if(p==m+1) return Po[n];ll ToT=0;for(int i=1;i<=n;i++) S[p].f[i]&&(ToT+=Po[n-i]);return ToT%mod;}
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d%d%d",&n,&m,&k);for(i=1;i<=n;i++) for(scanf("%s",s+1),j=1;j<=m;j++) S[j].f[n-i+1]=s[j]-'0';for(i=1;i<=m;i++) S[i].Id=i;
sort(S+1,S+m+1,cmp);for(i=1;i<=m;i++) Id[S[i].Id]=i;for(Po[0]=i=1;i<=n;i++) Po[i]=Po[i-1]*2%mod;
for(i=1;i<=n;i++) S[m+1].f[i]=1;while(k--){
scanf("%s",s+1);x=m+1;y=0;for(i=1;i<=m;i++) s[i]^'0'?(x=min(x,Id[i])):(y=max(y,Id[i]));
if(x<y){puts("0");continue;}printf("%lld\n",(calc(x)-calc(y)+mod)%mod);
}
}