CF1168B 构造+暴力
题意:给定一个长度为 \(n\) 的 \(01\) 串 \(s\),询问有多少个区间 \([l,r]\) 满足:\(\exists x,y\in[l,r]\),\(s_x,s_y,s_{x+y\over 2}\) 的值相同。
题解:直接暴力,利用下面这个结论可以说明复杂度是正确的。
结论:不存在长度超过 \(9\) 的不合法区间。
证明:
这里只证明对于一个无限长的串,保证存在相同值的两点及其中点。
考虑反证。取两个颜色相同的点 \(A,B\),不失一般性地令 \(A\)、\(B\) 对应的值为 \(1\)。对于其中点 \(C\),若不存在,则 \(C\) 的值为 \(0\)。
再考虑两点 \(C,D\),满足 \(|CA|=|AB|=|BD|\),现在考虑 \(C\) 的值:
- 当 \(C=1\) 时,由于 \(A=1,B=1\),于是存在,矛盾。
- 当 \(C=0\) 时,不难发现 \(D=0\),与 \(CD\) 中点组成了相同值的三点,矛盾。
综上,必定存在两点及其中点值相同。
代码很普通,就不放了
CF1391C 构造+找规律
题目大意:
给定一个长度为n的排列,求有多少种排列使得经过下列操作后图中存在环。操作的内容是一个排列中第i个位置向两边第一个比它大的位置连边。
题解:
观察性质,首先发现对于一个单调递增的序列和单调递减的序列一定不存在环(因为第i个点只连向下一个点)。
但是这样根据样例会发现会少算很多情况。手玩n=3的情况会发现1 3 2或者是2 3 1也是满足的,也就是对于单峰的序列都可以这样做。
这样的答案如何统计呢,不难发现,可以枚举最高点n所在的位置,剩下的数要考虑放在左边还是放在右边。稍微推了几个情况会发现,只要确定了剩下的数字的放置情况,就可以确定最高点的位置,注意到每个点有放在左边和放在右边两种情况,于是不存在环的情况共有2的n-1次方个。
答案就是n!-2^(n-1)。
CF706D trie树+贪心
题意:维护一个可重集,支持插入删除,以及给定x查询最大异或值
题解:垃圾trie题,不知道为什么写的很像线段树。。
#define N 200005
#define L 30
struct No{int c[2],s,v;}t[N<<5];
int n,rt,c,g;
void upd(int o){t[o].s=t[t[o].c[0]].s+t[t[o].c[1]].s;}
void ins(int&o,int x,int d,int b=L-1){
if(!o)o=++c;
if(b==-1){t[o].s+=d;t[o].v+=d;return;}
ins(t[o].c[(x>>b)&1],x,d,b-1);upd(o);
}
int que(int&o,int x,int d=0,int R=0,int b=L-1){
if(b==-1)return R;
if(t[t[o].c[!((x>>b)&1)]].s)return std::max(R,que(t[o].c[!((x>>b)&1)],x,1,R+(1<<b),b-1));
else return std::max(R,que(t[o].c[(x>>b)&1],x,0,R,b-1));
}
signed main(){
n=rd();
ins(rt,0,1);
jk(i,1,n){
g=getchar();
if(g=='?')P(que(rt,rd())),putchar('\n');
else ins(rt,rd(),g=='+'?1:-1);
}
}
CF61E 离散化+树状数组
题意:给定序列 \(\{a_i\},i=1...n\),求三元组 \((i,j,k)\) 满足 \(i<j<k\) 且 \(a_i>a_j>a_k\) 的个数,保证 \(\forall i, j\in[1,n]\) 且 \(i\neq j\),有 \(a_i\neq a_j\)。
题解:枚举中间点,相当于询问两边有多少点比它高/低,直接离散化然后建两个树状数组维护权值就好了。
#define N 1000010
#define lo(x) x&(-x)
int n,a[N],b[N],r;
struct BIT{
int t[N];
void ad(int x,int d){for(;x<=n;x+=lo(x))t[x]+=d;}
int qu(int x){int r=0;for(;x>=1;x-=lo(x))r+=t[x];return r;}
}L,R;
signed main(){
n=rd();jk(i,1,n)a[i]=b[i]=rd();
std::sort(b+1,b+n+1);
jk(i,1,n)a[i]=std::lower_bound(b+1,b+n+1,a[i])-b;
jk(i,1,n)R.ad(a[i],1);
jk(i,1,n){R.ad(a[i],-1);r+=R.qu(a[i])*(i-1-L.qu(a[i]));L.ad(a[i],1);}
P(r);
}
CF1354D 树状数组上二分
题意:给定一个不降序列 \(\{a_i\}\),需要支持插入一个数,删除第k大的数。卡空间,每个测试点28MB。
题解:直接树状数组上二分。
二分的代码,需要观察到和的一些性质
int kt(int x){
int R=0,c=0;
kj(i,20,0)if(R+(1<<i)<n&&c+t[R+(1<<i)]<x)R+=1<<i,c+=t[R];
return R+1;
}
完整代码:
#define N 1000005
#define lo(x) x&-x
int n,t[N+5],q,p,z;
void ad(int x,int d){for(;x<=n;x+=lo(x))t[x]+=d;}
int qu(int x){int r=0;for(;x;x-=lo(x))r+=t[x];return r;}
int kt(int x){int R=0,c=0;kj(i,20,0)if(R+(1<<i)<n&&c+t[R+(1<<i)]<x)R+=1<<i,c+=t[R];return R+1;}
signed main(){
z=n=rd();q=rd();jk(i,1,n)ad(rd(),1);
while(q--){p=rd();ad(p>0?p:kt(-p),(p>0)-(p<0));z+=(p>0)-(p<0);}
P(z?kt(z):0);
}