bzoj 4408: [Fjoi 2016]神秘数

额,一开始突然想到了如果能表示出连续的二进制位,就可以构造出连续的数了。。然后想了一下,不可做2333

于是又走上了扒题解的不归路。。

貌似题解就是推广一下??

如果能表示出[l,r]那么新加入一个数a,那么可以得到一个新的区间是[l+a,r+a],然后和 [l,r]and[l+a,r+a](and表示取并集)就是现在能表示的区间。

现在我们希望 [l,r]and[l+a,r+a]==[l,r+a] ,这样的话考虑a的加入顺序,显然是应该从小到大的。

而且,在[l,r]and[l+a,r+a]==[l,r+a]的条件下,a是可解的:l+a-1<=r+1 (且l==1)

现在,a是从小到大加入的,而r肯定是小于等于a的所有值得和,带入的话,就可以判断出当前的a是否成立,从而就知道是不是有答案了。

然后判断区间小于一个数,用主席树搞一下就就好了。

这样的话,a是迭代变大,大概log次就好。。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 inline int ra()
 5 {
 6     int x=0; char ch=getchar();
 7     while (ch<'0' || ch>'9') ch=getchar();
 8     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
 9     return x;
10 }
11 
12 const int maxn=100005;
13 const int N=maxn*40;
14 
15 int ls[N],rs[N],sum[N],tot;
16 int root[maxn],len;
17 void insert(int l, int r, int x, int &y, int pos, int val)
18 {
19     y=++tot; sum[y]=sum[x]+val;
20     if (l>=r) return;
21     int mid=l+r>>1;
22     ls[y]=ls[x]; rs[y]=rs[x];
23     if (pos<=mid) insert(l,mid,ls[x],ls[y],pos,val);
24         else insert(mid+1,r,rs[x],rs[y],pos,val);
25 }
26 int query(int x, int y, int pos)
27 {
28     int l=1,r=len-1,ans=0; x=root[x-1]; y=root[y];
29     while (l<r)
30     {
31         int mid=l+r>>1;
32         if (pos<=mid) x=ls[x],y=ls[y],r=mid;
33         else ans+=sum[ls[y]]-sum[ls[x]],l=mid+1,x=rs[x],y=rs[y];
34     }
35     return ans+sum[y]-sum[x];
36 }
37 
38 int n,a[maxn],num[maxn],ans;
39 int main(int argc, char const *argv[])
40 {
41     n=ra();
42     for (int i=1; i<=n; i++) num[i]=a[i]=ra();
43     sort(num+1,num+n+1);
44     len=unique(num+1,num+n+1)-num;
45     for (int i=1; i<=n; i++) a[i]=lower_bound(num+1,num+len,a[i])-num;
46     for (int i=1; i<=n; i++) insert(1,len-1,root[i-1],root[i],a[i],num[a[i]]);
47     int T=ra();
48     while (T--)
49     {
50         int l=ra(),r=ra(),t;
51         for (ans=1;;ans=t+1)
52         {
53             int orz=lower_bound(num+1,num+len,ans)-num;
54             orz=(orz==len || num[orz]>ans)?orz-1:orz;
55             t=query(l,r,orz);
56             if (t<ans) break;
57         }
58         printf("%d\n",ans);
59     }
60     return 0;
61 }

 

posted @ 2017-05-02 10:30  ws_ccd  阅读(148)  评论(0编辑  收藏  举报