模拟91 题解

A. Dove 打扑克

显然的结论是:超过$\sqrt n$的牌堆不会超过$\sqrt n$个。

所以可以分块维护信息:

对于牌数小于$\sqrt n$的,用一个桶维护。

对于牌数大于$\sqrt n$的,用$vector$暴力插入删除维护。

同时维护答案,为了做到$O(1)$修改,也用分块进行维护。

 

 

 

B. Cicada 与排序

值不同的数,位置一定是固定的。

所以可以只对值相同的数在类似归并的过程中进行$dp$。

考虑每一个值,设$dp_{i,j,dep}$表示这个值在原序列上出现的第$i$个副本,在归并排序深度为$dep$的意义下排名为$j$的概率。

处理出数组$g_{i,j}$表示归并排序过程中,两个指针分别指向$i,j$的概率,

$f_{i,j}$表示第$i$位转移到第$j$位的概率,可以在递推$g$数组的同时简单求出。

然后随便转移就完了。

 

 

 

C. Cicada 拿衣服

考虑题中给出的限制$min+or-max-and$。

不妨分别提出其中的$min-max,or-and$。

可以枚举当前考虑的右端点。

那么对于不同的左端点:

$or-and$只有$2*log max(a_i)$种不同的取值,

因为二进制位分别对应只增不减,只减不增。

$min-max$随着左端点不断减小单调递减。

那么可以枚举每一个不同的取值,这个可以用链表简单维护(其实用两个数组暴力重构就可以)。

二分求出符合要求的最靠左的位置就可以。

然而这样做的复杂度是$O(nlog^2n)$的,其实有一些无用的状态。

因为之要求最靠左的左端点,从左到右枚举左端点所在的区间,在第一个可行区间二分更新答案后结束枚举就完了。

为了二分时$O(1)$查询,可以使用ST表维护。

然而刚刚学到了新的数据结构猫树,而且还可以和$zkw$线段树一起用,所以打起来就很帅。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #define lch p<<1
 4 #define rch p<<1|1
 5 using namespace std;
 6 const int N=1e6+50007;
 7 struct node{
 8     int pos,And,Or;
 9 }sa[105],sb[105];
10 int n,k,bit,ca,cb;
11 int a[N],mx[22][N],mn[22][N],lg[N],ans[N<<1];
12 void build(int p,int l,int r,int dep){
13     if(l==r) return ;
14     int mid=l+r>>1;
15     build(lch,l,mid,dep+1);
16     build(rch,mid+1,r,dep+1);
17     mx[dep][mid]=mn[dep][mid]=a[mid];
18     mx[dep][mid+1]=mn[dep][mid+1]=a[mid+1];
19     for(int i=mid-1;i>=l;--i) mn[dep][i]=min(mn[dep][i+1],a[i]),mx[dep][i]=max(mx[dep][i+1],a[i]);
20     for(int i=mid+2;i<=r;++i) mn[dep][i]=min(mn[dep][i-1],a[i]),mx[dep][i]=max(mx[dep][i-1],a[i]);
21 }
22 void dfs(int p,int l,int r,int Ans){
23     Ans=max(Ans,ans[p]);
24     if(l==r){
25         if(l>1&&l<=n+1) printf("%d ",Ans);
26         return ;
27     }
28     int mid=l+r>>1;
29     dfs(lch,l,mid,Ans);
30     dfs(rch,mid+1,r,Ans);
31 }
32 inline int query_min(int l,int r){
33     if(l==r) return a[l];
34     int k=lg[bit]-lg[(l-1)^(r-1)];
35     return min(mn[k][l],mn[k][r]);
36 }
37 inline int query_max(int l,int r){
38     if(l==r) return a[l];
39     int k=lg[bit]-lg[(l-1)^(r-1)];
40     return max(mx[k][l],mx[k][r]);
41 }
42 inline void modify(int l,int r,int val){
43     for(l+=bit-1,r+=bit+1;l^r^1;l>>=1,r>>=1){
44         if(~l&1) ans[l^1]=max(ans[l^1],val);
45         if(r&1) ans[r^1]=max(ans[r^1],val);
46     }
47 }
48 inline int read(register int x=0,register char ch=getchar(),register int f=0){
49     for(;!isdigit(ch);ch=getchar()) f=ch=='-';
50     for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
51     return f?-x:x;
52 }
53 int main(){
54     n=read(); k=read();
55     for(int i=1;i<=n;++i) a[i]=read();
56     for(bit=1;bit<=n+1;bit<<=1);
57     for(int i=1;i<=bit;++i) lg[i]=lg[i>>1]+1;
58     for(int i=1;i<=bit+n;++i) ans[i]=-1;
59     build(1,1,bit,1);
60     for(int i=1;i<=n;++i){
61         for(int j=1;j<=ca;++j) sa[j].And&=a[i],sa[j].Or|=a[i];
62         sa[++ca]=(node){i,a[i],a[i]}; cb=0;
63         for(int j=1;j<=ca;++j) if(j==ca||sa[j].And!=sa[j+1].And||sa[j].Or!=sa[j+1].Or) sb[++cb]=sa[j];
64         for(int j=1;j<=cb;++j) sa[j]=sb[j];
65         ca=cb;
66         int flag=0;
67         for(int j=1;j<=ca&&!flag;++j)
68             if(sa[j].Or-sa[j].And+query_min(sa[j].pos,i)-query_max(sa[j].pos,i)>=k){
69                 int l=sa[j-1].pos+1,r=sa[j].pos;
70                 while(l<r){
71                     int mid=l+r>>1;
72                     if(sa[j].Or-sa[j].And+query_min(mid,i)-query_max(mid,i)>=k) r=mid;
73                     else l=mid+1;
74                 }
75                 modify(l,i,i-l+1);
76                 flag=1;
77             }
78     }
79     dfs(1,1,bit,-1);
80     return 0;
81 }

 

posted @ 2019-10-28 16:46  skyh  阅读(363)  评论(4编辑  收藏  举报