csp-s模拟测试52平均数,序列题解
题面:https://www.cnblogs.com/Juve/articles/11602244.html
平均数:
第k个平均数不好求,我们考虑二分,转化成平均数小于x的有几个
虑把序列中的每个数减去 x,则我们只需求区间和小于 0 的区间数量。
我们对这个序列求前缀和,则区间[L,R]和小于 0 当且仅当 SL-1>SR,
答案即为前缀和序列 S 的逆序对数量,使用经典的归并排序即可解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define int long long #define double long double using namespace std; const int MAXN=1e5+5; int n,k,ans=0; double L=0.0,R=1e9+1,sum[MAXN],temp[MAXN],res,a[MAXN]; double max( double a, double b){ return a>b?a:b; } void merge_sort( int l, int r){ int mid,i,j,k; if (l==r) return ; mid=(l+r)/2; merge_sort(l,mid);merge_sort(mid+1,r); i=l;j=mid+1;k=l; while (i<=mid&&j<=r){ if (sum[i]>sum[j]){ ans+=mid-i+1; temp[k]=sum[j]; j++; k++; } else { temp[k]=sum[i]; i++; k++; } } while (i<=mid){ temp[k]=sum[i]; i++; k++; } while (j<=r){ temp[k]=sum[j]; j++; k++; } for (i=l;i<=r;i++) sum[i]=temp[i]; } bool check( double x){ ans=0; sum[0]=0; for ( int i=1;i<=n;++i){ sum[i]=sum[i-1]+a[i]-x; } merge_sort(0,n); return ans<k; } signed main(){ scanf ( "%lld%lld" ,&n,&k); for ( int i=1;i<=n;++i){ scanf ( "%Lf" ,&a[i]); } while (L<R-(1e-5)){ double mid=(L+R)/2.0; if (check(mid)) L=mid; else R=mid; } printf ( "%0.4Lf\n" ,L); return 0; } |
序列:
考虑主席树,相当与对每一个位置建一棵动态开点权值线段树,
我们不能把所有区间插进去,我们插入询问,对于每一个位置,经过它的询问有很多,我们统计a[i]对整个答案的贡献
我们对每一个位置插入所有在这个位置上要查询的x,然后答案就是对于每一个位置i,在i所在的线段树中找小于a[i]的x的数量,这是a[i]对整个答案的贡献
修改后我们还像之前那样查询,如果将p位置更改为v,那么减去a[p]的贡献,在加上更改后的v对整个答案的贡献
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define int long long #define re register using namespace std; const int MAXN=1e5+5; int n,m,q,a[MAXN],ans,x[MAXN]; int root[MAXN],tot=0,ls[MAXN<<6],rs[MAXN<<6],tr[MAXN<<6]; struct node{ int pos,val; }; vector<node>v[MAXN]; inline void insert(re int &k,re int pre,re int l,re int r,re int pos,re int val){ k=++tot; ls[k]=ls[pre],rs[k]=rs[pre],tr[k]=tr[pre]; if (l==r){ tr[k]+=val; return ; } re int mid=(l+r)>>1; if (pos<=mid) insert(ls[k],ls[pre],l,mid,pos,val); else insert(rs[k],rs[pre],mid+1,r,pos,val); tr[k]=tr[ls[k]]+tr[rs[k]]; } inline int query(re int k,re int l,re int r,re int opl,re int opr){ if (opl<=l&&r<=opr) return tr[k]; re int mid=(l+r)>>1,res=0; if (opl<=mid) res+=query(ls[k],l,mid,opl,opr); if (opr>mid) res+=query(rs[k],mid+1,r,opl,opr); return res; } signed main(){ scanf ( "%lld%lld%lld" ,&n,&m,&q); for (re int i=1;i<=n;++i){ scanf ( "%lld" ,&a[i]); } for (re int i=1,l,r;i<=m;++i){ scanf ( "%lld%lld%lld" ,&l,&r,&x[i]); v[l].push_back((node){x[i],1}); v[r+1].push_back((node){x[i],-1}); } for (re int i=1;i<=n;++i){ root[i]=root[i-1]; int N=v[i].size(); for (re int j=0;j<N;++j){ insert(root[i],root[i],1,n,v[i][j].pos,v[i][j].val); } } for (re int i=1;i<=n;++i){ ans+=query(root[i],1,n,1,a[i]); } printf ( "%lld\n" ,ans); for (re int i=1,p,v;i<=q;++i){ scanf ( "%lld%lld" ,&p,&v); p^=ans,v^=ans; ans+=(query(root[p],1,n,1,v)-query(root[p],1,n,1,a[p])); a[p]=v; printf ( "%lld\n" ,ans); } return 0; } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何在 .NET 中 使用 ANTLR4
· 后端思维之高并发处理方案
· 理解Rust引用及其生命周期标识(下)
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· Cursor预测程序员行业倒计时:CTO应做好50%裁员计划
· 想让你多爱自己一些的开源计时器
· 大模型 Token 究竟是啥:图解大模型Token
· 用99元买的服务器搭一套CI/CD系统
· 如何在 .NET 中 使用 ANTLR4