[考试反思]1107csp-s模拟测试104: 速度
20分钟能做什么?
不粘排行榜,没意义,第一机房集体重启,我侥幸找回了两个文件才有分。
实际得分应该是70+100+60,第二机房rank1。。。放在第一机房就不知道了
T1:中间值
比较喜欢题解的第二种做法。
考虑分治。现在要求出a[l,r],b[L,R]之内的第k小值。
递归边界:如果k==1,那么就是min(a[l],b[L])。如果一个区间为空,直接返回另一个区间的第k小值。
否则我们在a和b中分别取出一些元素,与k的一半取min,然后比较这个元素
即设t=min(k>>1,r-l+1).
那么我们可以比较a[l+t]与b[L+k-t]。较小的一边就可以排除了,继续递归解决即可。
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,a[],b[];
int read(){
register int p=,nt=;register char ch=getchar();
for(;ch<''||ch>'';ch=getchar())nt=ch=='-';
for(;ch>=''&&ch<='';p=(p<<)+(p<<)+ch-,ch=getchar());
return nt?-p:p;
}
int chk(int l,int r,int L,int R,int k){//printf("%d %d %d %d %d\n",l,r,L,R,k);
if(k==)return min(a[l],b[L]);
if(l>r)return b[L+k-];
if(L>R)return a[l+k-];
int t=min(min(r-l+,R-L+),k>>);
if(a[l+t-]>b[L+t-])return chk(l,r,L+t,R,k-t);
else return chk(l+t,r,L,R,k-t);
}
int main(){
freopen("median.in","r",stdin);freopen("median.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)a[i]=read();
for(int i=;i<=n;++i)b[i]=read();
while(m--){
int opt;scanf("%d",&opt);
if(opt==){
int x=read(),y=read(),z=read();
if(!x)a[y]=z;else b[y]=z;
}else{
int l=read(),r=read(),L=read(),R=read(),cnt;
printf("%d\n",chk(l,r,L,R,R-L+r-l+>>));
}
}
}
T2:最小值
感觉像单调栈,但是单调栈里的值都可能是最优决策。
发现转移值与当前点位置无关,所以直接把转移值放进set。弹栈时删除。
#include<cstdio>
#include<set>
using namespace std;
#define inf -12345678901234567
multiset<long long>S;
long long A,B,C,D,dp[],val[];int n,x[],s[],tp;
long long cal(int x){return A*x*x*x+B*x*x+C*x+D;}
struct Segment_Tree{
long long w[];
void modify(int p,int pos,long long v,int cl=,int cr=n){
if(cl==cr){w[p]=v;return;}
if(pos<=cl+cr>>)modify(p<<,pos,v,cl,cl+cr>>);
else modify(p<<|,pos,v,(cl+cr>>)+,cr);
w[p]=max(w[p<<],w[p<<|]);
}
long long ask(int p,int l,int r,int cl=,int cr=n){
if(l<=cl&&cr<=r)return w[p];
return max(l<=cl+cr>>?ask(p<<,l,r,cl,cl+cr>>):inf,r>cl+cr>>?ask(p<<|,l,r,(cl+cr>>)+,cr):inf);
}
}T;
int main(){
freopen("min.in","r",stdin);freopen("min.out","w",stdout);
scanf("%d%lld%lld%lld%lld",&n,&A,&B,&C,&D);
for(int i=;i<=n;++i)scanf("%d",&x[i]);
for(int i=;i<=n;++i){
while(tp&&x[s[tp]]>x[i])S.erase(S.find(val[tp])),tp--;
s[++tp]=i;val[tp]=T.ask(,s[tp-],i-)+cal(x[i]);S.insert(val[tp]);
dp[i]=*(--S.end());T.modify(,i,dp[i]);
}printf("%lld\n",dp[n]);
}
T3:最大值
写的不是题解思路,稍麻烦,码量较大,思维量较大,较麻烦,常数也稍大(需要zkw+fread+取模优化并且还不能乱开long long才能卡过。。。)
可以发现,因为不包含,所以询问按左端点排序之后,右端点也就单调了。
所以其实可以两个单调指针扫一遍,操作就类似于莫队了。
每个魔法阵内部的各种取值的概率比较好计算,从小到大依次考虑,每个元素的概率就是前面所有项$1-p$的乘积再乘这个取值的p。
对于剩下的概率,还要加入一个0。
关键在于魔法阵之间的影响。
暴力的思路就是把区间内的魔法阵都加入set,然后按照和上面一样的方法依次考虑。
只不过要注意,对于任意一个可能值,它的概率都不会受到他自己来源的魔法阵的影响,需要除去。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mod 1000000007
#define ip(p) (1000000008-p)
int qpow(int b,int t,int a=){for(;t;t>>=,b=b*b%mod)if(t&)a=a*b%mod;return a;}
#define inv(p) qpow(p,mod-2)
struct P{
int w,p,b;
friend bool operator<(P a,P b){return a.w<b.w;}
}p;
struct Q{
int l,r;
friend bool operator<(Q a,Q b){return a.l<b.l;}
}qs[];
vector<P>v[],V[];
multiset<P>S;
int n,m,q,alpos[],ans;
main(){freopen("max.in","r",stdin);freopen("max.out","w",stdout);
scanf("%lld%lld%lld",&n,&m,&q);
for(int i=;i<=m;++i)scanf("%lld%lld%lld",&p.b,&p.w,&p.p),v[p.b].push_back(p);
for(int i=;i<=n;++i){
sort(v[i].begin(),v[i].end());
int rpos=;
for(int j=;j<v[i].size();++j)V[i].push_back((P){v[i][j].w,v[i][j].p*rpos%mod,i}),rpos=rpos*ip(v[i][j].p)%mod;
V[i].push_back((P){,rpos,i});
}
for(int i=;i<=q;++i)scanf("%lld%lld",&qs[i].l,&qs[i].r);
sort(qs+,qs++q);qs[].l=;
for(int i=;i<=q;++i){
for(int j=qs[i-].r+;j<=qs[i].r;++j)for(int k=;k<V[j].size();++k)S.insert(V[j][k]);
for(int j=qs[i-].l;j<qs[i].l;++j)for(int k=;k<V[j].size();++k)S.erase(S.find(V[j][k]));
int rpos=;
for(int j=qs[i].l;j<=qs[i].r;++j)alpos[j]=;
for(set<P>::reverse_iterator it=S.rbegin();it!=S.rend();++it){P It=*it;
rpos=(rpos*inv(alpos[It.b]))%mod;
ans=(ans+rpos*It.p%mod*It.w)%mod;
alpos[It.b]=(mod+alpos[It.b]-It.p)%mod;
rpos=rpos*alpos[It.b]%mod;
}
}printf("%lld\n",ans);
}
60分暴力
考虑线段树维护。离散化,下标为水晶的能量。
为了方便处理(并且保证答案正确),我们要强制所有能量值相等的水晶有固定的先后次序,加一个没有意义的第二关键字来进行排序。
(否则的话,对于一个同一个能量值的水晶,它们互相影响就会导致答案值偏小)
就是不存在A限制了B的同时B也限制了A的情况(自己举个权值相同的例子就好)
然后你依次考虑每一个水晶,它会产生的影响是:来自其它魔法阵的能量值更小及相等的晶石产生贡献的概率要乘上1-p。然后当然要把自己的出现概率累加。
线段树维护区间乘,单点加。并没有区间查询,因为你每次查询都是查的整棵树,及时uodate,最后直接拿1号点的权值就好了。
注意这里的区间乘法是要持续生效的,不只作用于当前值,也就是以后再加入某一个值的时候,还要再乘上以前的乘法标记。
所以采用了标记永久化。
要注意一些地方:一个晶石并不会对来自与同一魔法阵的晶石产生影响,但是乘法标记是区间一起打上的不能区分,所以在进行区间加的时候,还要除以以前来自同一魔法阵所打上的乘法标记。
同时还要再考虑,你区间乘好像是每次都从1到某一个位置,那么来自同一个魔法阵的晶石可能对低位产生了多次影响。
所以在下一个晶石乘的时候,还要把它控制的区间内它之前的一颗晶石产生的影响删除(就是乘逆元)
然后还要考虑从线段树里删除魔法阵。
单点加变减。区间乘变乘逆元。
看起来没有什么问题。但是当你发现需要乘0的时候世界就崩塌了。
区间乘0其实还好说,关键是以后在删除魔法阵时还要消除这个乘0的影响。
乘0的逆元?不存在啊。
所以线段树上还要特殊处理一下乘0的标记。每次乘的时候标记+1,每次乘“0的逆元”时标记-1。
只要有标记存在,就证明这段区间的概率都是0,所以对答案的贡献也就是0。
在代码里我就把“0的逆元”设定为-1了。
然后就是卡常。。。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
int Mod(ll x){return x>=mod?x-mod:x;}
const int L=<<|;
char buffer[L],*S,*Q;
#define getchar() ((S==Q&&(Q=(S=buffer)+fread(buffer,1,L,stdin),S==Q))?EOF:*S++)
const int maxn=+;
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
ll qpow(ll b,int t,ll a=){for(;t;t>>=,b=b*b%mod)if(t&)a=a*b%mod;return a;}
struct P{
ll w,p;int b,rk;
friend bool operator<(P a,P b){return a.w<b.w;}
}p;
struct N{
ll w;int ord;
friend bool operator<(N a,N b){return a.w<b.w||(a.w==b.w&&a.ord<b.ord);}
}W[];
ll inv(ll p){return p?qpow(p,mod-):-;}
ll ip(ll p){return (mod+-p)%mod;}
vector<P>v[],V[];
int n,m,q,K,k,l[],r[];ll ans;
struct Segment_Tree{
ll w[],lz[];int NONE[];
int cal(int p){return NONE[p]?:lz[p]*w[p]%mod;}
int bit;
void build(){
for(bit=;bit<=k+;bit<<=);
for(int i=;i<=bit+bit;++i) lz[i]=;
}
void mult(int l,int r,ll v){
for(l+=bit-,r+=bit+;l^r^;){
if(~l&){
if(v>) lz[l^]=lz[l^]*v%mod;
else if(!v)NONE[l^]++;
else NONE[l^]--;
}
if(r&){
if(v>) lz[r^]=lz[r^]*v%mod;
else if(!v)NONE[r^]++;
else NONE[r^]--;
}
l>>=; r>>=;
w[l]=Mod(cal(l<<)+cal(l<<|));
w[r]=Mod(cal(r<<)+cal(r<<|));
}
for(l>>=;l;l>>=) w[l]=Mod(cal(l<<)+cal(l<<|));
}
void add(int p,ll v){
p+=bit; w[p]=(w[p]+v*W[p-bit].w)%mod;
for(p>>=;p;p>>=) w[p]=Mod(cal(p<<)+cal(p<<|));
}
}T;
bool com(P a,P b){return a.w>b.w;}
main(){
freopen("max.in","r",stdin);
freopen("max.out","w",stdout);
scanf("%d%d%d",&n,&m,&q);
for(int i=;i<=m;++i)p.b=read(),p.w=read(),p.p=read(),v[p.b].push_back(p);
for(int i=;i<=n;++i){
sort(v[i].begin(),v[i].end());
ll rpos=;
for(int j=;j<v[i].size();++j)V[i].push_back((P){v[i][j].w,v[i][j].p*rpos%mod,i,++K}),rpos=rpos*ip(v[i][j].p)%mod;
V[i].push_back((P){,rpos,i,++K});
}
for(int i=;i<=n;++i)for(int j=;j<V[i].size();++j)W[++k]=(N){V[i][j].w,V[i][j].rk};
sort(W+,W++k);T.build();
for(int i=;i<=n;++i)for(int j=;j<V[i].size();++j)V[i][j].w=lower_bound(W+,W++k,(N){V[i][j].w,V[i][j].rk})-W;
for(int i=;i<=n;++i)sort(V[i].begin(),V[i].end(),com);
for(int i=;i<=q;++i)l[i]=read(),r[i]=read();
l[]=;
for(int i=;i<=q;++i){
for(int j=r[i-]+;j<=r[i];++j){
ll totpos=;
for(int k=;k<V[j].size();++k){
if(V[j][k].p==)continue;
ll TP=totpos;totpos=Mod(totpos+V[j][k].p);
T.mult(,V[j][k].w-,ip(totpos));
if(k)T.mult(,V[j][k].w,inv(ip(TP)));
T.add(V[j][k].w,V[j][k].p);
}
}
for(int j=l[i-];j<l[i];++j){
ll totpos=;
for(int k=;k<V[j].size();++k){
if(V[j][k].p==)continue;
totpos=Mod(totpos+V[j][k].p);
T.mult(,V[j][k].w-,inv(ip(totpos)));
if(k)T.mult(,V[j][k].w-,ip(totpos-V[j][k].p));
T.add(V[j][k].w,mod-V[j][k].p);
}
}
ans=(ans+T.w[]*T.lz[])%mod;
}printf("%lld\n",ans);
}
因为细节实在太多,所以哪个地方不会的话在评论区里问,一个一个细节来讲肯定是说不完的。。。
[考试反思]1107csp-s模拟测试104: 速度的更多相关文章
- [考试反思]0718 NOIP模拟测试5
最后一个是我...rank#11 rank#1和rank#2被外校大佬包揽了. 啊...考的太烂说话底气不足... 我考场上在干些什么啊!!! 20分钟“切”掉T2,又27分钟“切”掉T1 切什么切, ...
- [考试反思]0814NOIP模拟测试21
前两名是外校的240.220.kx和skyh拿到了190的[暴力打满]的好成绩. 我第5是170分,然而160分就是第19了. 在前一晚上刚刚爆炸完毕后,心态格外平稳. 想想前一天晚上的挣扎: 啊啊啊 ...
- [考试反思]1109csp-s模拟测试106:撞词
(撞哈希了用了模拟测试28的词,所以这次就叫撞词吧) 蓝色的0... 蓝色的0... 都该联赛了还能CE呢... 考试结束前15分钟左右,期望得分300 然后对拍发现T2伪了写了一个能拿90分的垃圾随 ...
- [考试反思]1003csp-s模拟测试58:沉淀
稳住阵脚. 还可以. 至少想拿到的分都拿到了,最后一题的确因为不会按秩合并和线段树分治而想不出来. 对拍了,暴力都拍了.挺稳的. 但是其实也有波折,险些被卡内存. 如果内存使用不连续或申请的内存全部使 ...
- [考试反思]0909csp-s模拟测试41:反典
说在前面:我是反面典型!!!不要学我!!! 说在前面:向rank1某脸学习,不管是什么题都在考试反思后面稍微写一下题解. 这次是真的真的运气好... 这次知识点上还可以,但是答题策略出了问题... 幸 ...
- [考试反思]0729NOIP模拟测试10
安度因:哇哦. 安度因:谢谢你. 第三个rank1不知为什么就来了.迷之二连?也不知道哪里来的rp 连续两次考试数学都占了比较大的比重,所以我非常幸运的得以发挥我的优势(也许是优势吧,反正数学里基本没 ...
- [考试反思]0714/0716,NOIP模拟测试3/4
这几天时间比较紧啊(其实只是我效率有点低我在考虑要不要坐到后面去吹空调) 但是不管怎么说,考试反思还是要写的吧. 第三次考试反思没写总感觉缺了点什么,但是题都刷不完... 一进图论看他们刷题好快啊为什 ...
- [考试反思]0816NOIP模拟测试23
210 210 210 170 还可以.暴力打满就rk4了? 但不管怎么说,总算是在改完题之后理直气壮的写考试反思了. T1是个dp,说水也不太水.(当然某脸只要A掉了一道题就要说那是水题) 我的思路 ...
- [考试反思]0801NOIP模拟测试11
8月开门红. 放假回来果然像是神志不清一样. 但还是要接受这个事实. 嗯,说好听点,并列rank#7. 说难听点,垃圾rank#18. 都不用粘人名就知道我是哪一个吧... 因为图片不能太长,所以就不 ...
随机推荐
- 文本数据IO操作--字符流
一.Reader和Writer 1. 字符流原理 Reader是所有字符输入流的父类而Writer是所有字符输出流的父类.字符流是以字符(char)为单位读写数据的.一次处理一个unicode.字符流 ...
- [以太坊源代码分析] I.区块和交易,合约和虚拟机
最近在看以太坊(Ethereum)的源代码, 初初看出点眉目. 区块链是近年热点之一,面向大众读者介绍概念的文章无数,有兴趣的朋友可自行搜索.我会从源代码实现入手,较系统的介绍一下以太坊的系统设计和协 ...
- Python 命令行参数解析工具 argparse
为什么需要argparse 开门见山,举一个简易计算器代码的例子,其中sys.argv用来读取脚本执行时后面传入的参数. def calculator(x, y, operation): if &qu ...
- spring源码分析系列5:ApplicationContext的初始化与Bean生命周期
回顾Bean与BeanDefinition的关系. BeanFactory容器. ApplicationContext上下文. 首先总结下: 开发人员定义Bean信息:分为XML形式定义:注解式定义 ...
- 数据存储检索之B+树和LSM-Tree
作为一名应用系统开发人员,为什么要关注数据内部的存储和检索呢?首先,你不太可能从头开始实现一套自己的存储引擎,往往需要从众多现有的存储引擎中选择一个适合自己应用的存储引擎.因此,为了针对你特定的工作负 ...
- BBEdit 13.0 for Mac 打开大文件不吃力
BBEdit 是一款拥有 16 年历史的 HTML 和文本编辑器,拥有高性能且流畅的文本处理能力,适用于 Web 和软件开发者,具备功能丰富且强大的智能搜索.代码折叠.FTP 和 SFTP 管理等功能 ...
- [NOIp2011] luogu P1314 聪明的质监员
题目描述 点进去看吧,说的不能再清楚了. Solution 看到数据规模不难想到二分 WWW,然后用个前缀和优化一下即可.注意上下界. #include<cstdio> #include& ...
- [LUOGU1272] 重建道路 - 树形背包
题目描述 一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场.由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的.因此,牧场运输系 ...
- Cocos2d-x 学习笔记(20) ControlButton
[Cocos2d-x 学习笔记 目录链接] 1. 简介 ControlButton实现了按钮功能,根据触摸的位置和移动的过程可识别9中EventType类型,执行对应的回调函数. 直接继承了Contr ...
- Kubernetes的Ingress简单入门
目录 一.什么是Ingress 二.部署Nginx Ingress Controller 三.部署一个Service将Nginx服务暴露出去 四.部署一个我们自己的服务Cafe 五.部署ingress ...