这里是 $THUWC$ 选拔时间
模拟赛的时候犯 $SB$ 了,写了所有的部分分,然后直接跑过了 $4$ 个大样例(一个大样例是一个特殊情况)……
我还以为我非常叼,部分分都写对了,于是就不管了……
离考试结束还有 $10$ 分钟的时候才发现……程序跑暴力的条件写的是 $$if(n<=5000)\space force::solve();$$
由于 $4$ 个大样例的 $n$ 都只有几百,我之前测的全是暴力……
然后赶紧改改改,测了三个部分分的程序,都小错不断……
于是最后调不完了,自闭 -_-。当做是一次教训吧。
题解
这道题的部分分给得很足,所以这里都说一下。
另外,我在下文直接把“新生舞会的数”简称为“众数”,虽然两者定义不一样,但我想少打点字。
type=1
只要区间内 $0,1$ 的数量不相等,就一定有一个众数($type=3$ 的部分会提到这叫“绝对众数”)。
所以把 $1$ 看成 $1$,$0$ 看成 $-1$,就变成问有多少对不相等的前缀和。
把所有前缀和桶排后随便乘一乘即可。
type=2
区间的众数不会出现超过 $15$ 次,也就是说满足要求的区间长度不会超过 $29$。
暴力枚举所有长度为 $1$ 到 $29$ 的区间即可。
type=3
此时只有 $8$ 种众数。
由于一个区间内只有一个众数(绝对众数),所以我们可以枚举众数,然后找这个数是哪些区间的众数。
当设众数为 $x$ 时,把 $x$ 记为 $1$,其它数记为 $-1$,那么就是要找所有和 $\ge 1$ 的区间。
改成线性推:假设第 $1$ 到 $i$ 位的和为 $y$(也就是第 $i$ 位的前缀和),那就要快速查找前面有多少和 $\lt y$ 的前缀。
这就是线段树维护前缀和的裸题了。
1 #include<bits/stdc++.h> 2 #define N 500005 3 #define ll long long 4 #define rep(i,x,y) for(int i=x;i<=y;++i) 5 #define lc o<<1 6 #define rc o<<1|1 7 using namespace std; 8 inline int read(){ 9 int x=0; bool f=1; char c=getchar(); 10 for(;!isdigit(c);c=getchar()) if(c=='-') f=0; 11 for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); 12 if(f) return x; 13 return 0-x; 14 } 15 int n,type,a[N]; 16 namespace force{ 17 ll ans; 18 int cnt[2001][2001]; 19 void solve(){ 20 rep(i,1,n){ 21 int mx=0; 22 for(int j=0;i+j<=n;++j){ 23 mx=max(mx,++cnt[i][a[i+j]]); 24 if(mx*2>j+1) ++ans; 25 } 26 } 27 cout<<ans<<endl; 28 } 29 }; 30 namespace type2{ 31 ll ans; 32 struct Tree{int siz; bool clr;}tr[N<<2]; 33 int v; 34 inline void pushdown(int o){ 35 if(tr[o].clr) 36 tr[lc].siz=tr[rc].siz=0, 37 tr[lc].clr=tr[rc].clr=1, 38 tr[o].clr=0; 39 } 40 int ins(int o,int l,int r){ 41 ++tr[o].siz; 42 if(l==r) return tr[o].siz; 43 pushdown(o); 44 int mid=(l+r)>>1; 45 if(v<=mid) return ins(lc,l,mid); 46 else return ins(rc,mid+1,r); 47 } 48 void solve(){ 49 rep(i,1,n){ 50 tr[1].siz=0, tr[1].clr=1; 51 int mx=0; 52 for(int j=0; j<29 && i+j<=n; ++j){ 53 v=a[i+j]; 54 mx=max(mx,ins(1,0,n-1)); 55 if(mx*2>j+1) ++ans; 56 } 57 } 58 cout<<ans<<endl; 59 } 60 }; 61 namespace type3{ 62 ll ans; 63 int L=-500000,R,v; 64 struct Tree{ 65 int siz[N<<2]; 66 void ins(int o,int l,int r){ 67 ++siz[o]; 68 if(l==r) return; 69 int mid=(l+r)>>1; 70 if(v<=mid) ins(lc,l,mid); 71 else ins(rc,mid+1,r); 72 } 73 int query(int o,int l,int r){ 74 if(L<=l && r<=R) return siz[o]; 75 int mid=(l+r)>>1, ret=0; 76 if(L<=mid) ret+=query(lc,l,mid); 77 if(R>mid) ret+=query(rc,mid+1,r); 78 return ret; 79 } 80 }tr[8]; 81 82 int sum[8]; 83 void solve(){ 84 rep(i,0,7) v=0, tr[i].ins(1,-500000,500000); 85 rep(i,1,n){ 86 rep(j,0,7) --sum[j]; 87 sum[a[i]]+=2; 88 rep(j,0,7){ 89 R=sum[j]-1; 90 if(L<=R) ans+=tr[j].query(1,-500000,500000); 91 v=sum[j]; 92 tr[j].ins(1,-500000,500000); 93 } 94 } 95 cout<<ans<<endl; 96 } 97 }; 98 int main(){ 99 n=read(),type=read(); 100 rep(i,1,n) a[i]=read(); 101 if(type==0) force::solve(); 102 else if(type==1 || type==3) type3::solve(); 103 else type2::solve(); 104 return 0; 105 }