预祝2025省选嗨翻天
\(T1\) A. 单峰序列 \(8pts\)
-
部分分
- \(8pts\) :枚举每个数在单峰序列的左边还是右边,求次数做法同 luogu P3531 [POI 2012] LIT-Letters 。
点击查看代码
int a[500010],b[500010],c[500010],ans[500010],id; vector<int>l,r; struct BIT {int c[500010];int lowbit(int x){return (x&(-x));}void add(int n,int x,int val){for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;}int getsum(int x){int ans=0;for(int i=x;i>=1;i-=lowbit(i)) ans+=c[i];return ans;} }T; void dfs(int pos,int n) {if(pos==n+1){b[0]=0;for(int i=0;i<l.size();i++){b[0]++; b[b[0]]=l[i];}sort(b+1,b+1+b[0]);b[0]++; b[b[0]]=a[id];int tmp=b[0]+1;for(int i=0;i<r.size();i++){b[0]++; b[b[0]]=r[i];}sort(b+tmp,b+1+b[0],greater<int>());for(int i=1;i<=n;i++) c[b[i]]=i;for(int i=1;i<=n;i++) tmp=0;for(int i=n;i>=1;i--){tmp+=T.getsum(c[a[i]]-1); T.add(n,c[a[i]],1);}ans[n]=min(ans[n],tmp);for(int i=1;i<=n;i++) T.add(n,c[a[i]],-1);}else{if(pos==id) dfs(pos+1,n);else{l.push_back(a[pos]); dfs(pos+1,n); l.pop_back();r.push_back(a[pos]); dfs(pos+1,n); r.pop_back();}} } int main() { #define Isaac #ifdef Isaacfreopen("seq.in","r",stdin);freopen("seq.out","w",stdout); #endifint n,t,i;cin>>n>>t;memset(ans,0x3f,sizeof(ans));for(i=1;i<=n;i++){cin>>a[i];if(a[i]>a[id]) id=i;dfs(1,i);}if(t==1) for(i=1;i<=n;i++) cout<<ans[i]<<endl;else cout<<ans[n]<<endl;return 0; }
-
正解
- 考虑 \(a_{x}\) 在最终单峰序列中位于 \(a_{k}\) 前还是 \(a_{k}\) 后,两者产生的逆序对/交换次数分别为 \(\sum\limits_{i=1}^{x-1}[a_{i}>a_{x}],\sum\limits_{i=x+1}^{r}[a_{i}>a_{x}]\) ,不妨设两个值分别为 \(p_{x},q_{x,r}\) 。贪心地取 \(\min(p_{x},q_{x,r})\) 作为其贡献即可。
- 观察到 \(q_{x,r}\) 随着 \(r\) 单调不降,考虑二分找到其分界点 \(limit_{x}\) 使得 \(limit_{x}\) 以前 \(p_{x} \ge q_{x,r}\) , \(limit_{x}\) 以后 \(p_{x}<q_{x,r}\) 。
- 动态维护 \(q_{x,r}\) 的变化,此时是一个矩阵加、单点查询的形式,扫描线即可。
点击查看代码
ll a[500010],pos[500010],sum[500010]; vector<ll>c[500010]; struct BIT {ll c[500010];ll lowbit(ll x){return (x&(-x));}void clear(){memset(c,0,sizeof(c));}void add(ll n,ll x,ll val){for(ll i=x;i<=n;i+=lowbit(i)) c[i]+=val;}void update(ll n,ll l,ll r,ll val){add(n,l,val); add(n,r+1,-val);}ll getsum(ll x){ll ans=0;for(ll i=x;i>=1;i-=lowbit(i)) ans+=c[i];return ans;} }B[2]; int main() { #define Isaac #ifdef Isaacfreopen("seq.in","r",stdin);freopen("seq.out","w",stdout); #endifll n,t,ans,l,r,mid,i,j;scanf("%lld%lld",&n,&t);for(i=1;i<=n;i++){scanf("%lld",&a[i]); pos[a[i]]=i;B[0].add(n,a[i],1);sum[i]=i-B[0].getsum(a[i]);}B[0].clear();for(i=n;i>=1;i--){l=pos[i]; r=n; ans=0;while(l<=r){mid=(l+r)/2;if(B[0].getsum(mid)-B[0].getsum(pos[i])<=sum[pos[i]]){ans=mid;l=mid+1;}else r=mid-1;}c[ans+1].push_back(a[pos[i]]);B[0].add(n,pos[i],1);}ans=0;for(i=1;i<=n;i++){if(a[i]+1<=n) B[1].update(n,a[i]+1,n,1);for(j=0;j<c[i].size();j++) B[1].update(n,c[i][j],n,-1);ans+=B[1].getsum(a[i]);if(i==n||t==1) printf("%lld\n",ans);}return 0; }
\(T2\) B. 划分线段 \(10pts\)
-
原题: CF1510H Hard Optimization
-
部分分
- \(10pts\) :输出 \(\max(r_{2}-l_{1},r_{1}-l_{2})\) 。
-
正解
\(T3\) C. 红蓝树 \(20pts\)
-
部分分
- \(20pts\) :模拟。
点击查看代码
int a[600010]; stack<int>s; int main() { #define Isaac #ifdef Isaacfreopen("rbtree.in","r",stdin);freopen("rbtree.out","w",stdout); #endifint n,m,pd,l,r,ans=0,col,i,j;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) {scanf("%d",&a[i]); a[i]--;}for(j=1;j<=m;j++){scanf("%d%d%d",&pd,&l,&r);if(pd==1) for(i=l;i<=r;i++) a[i]^=1;else{ans=col=0;while(s.empty()==0) s.pop();for(i=l;i<=r;i++){if(a[i]<=1){ans+=(a[i]||col); s.push((a[i]||col));col=0;}else if(s.empty()==0){col|=s.top();s.pop();}}printf("%d\n",ans);}}return 0; }
-
正解
总结
- 罚坐。