[bzoj4373]算术天才⑨与等差数列 解题报告
来源:互联网 发布:南风知我意2全文下载 编辑:程序博客网 时间:2024/05/18 02:09
先来说一下傻逼的做法。
考虑如何约束等差数列这个条件,如果k=0,就是[最大值=最小值];否则就是区间中[相邻两数差的绝对值的gcd=k][(最大值-最小值)/(r-l)=k][区间中没有相同元素]。
gcd可以用线段树求,这个东西看起来是
所以问题就在于怎么确定区间中没有相同元素。
显然,如果记每个位置下一个和它权值相同的位置在哪,那就转化成了求区间最小值的问题。而这个玩意儿其实就是求后继。本来想用主席树求,但是mle了。。所以就写了个平衡树。正好学一下treap。。
treap竟然可以不保存父指针,还是有点厉害的。。插入和删除感觉其实跟普通的二叉堆差不多。就是要善用引用。
膜拜一下大爷的做法。
注意到这玩意儿是个子串,所以这个东西是可以hash的。比如说我们可以把区间中的每个数平方相加,然后与我们需要的等差数列的每个数的平方和check。(为什么不直接相加呢?因为那样很容易被小数据卡跪。。)为了跑得更快,显然我们需要自然溢出,但是这样做的话需要除6,所以我们把它们整体乘6即可。
代码(线段树+平衡树):
#include<cstdio>#include<iostream>using namespace std;#include<algorithm>#include<cstring>#include<cmath>#include<cstdlib>#include<cassert>const int N=3e5+5,M=3e5+5;int a[N];int n;void in(int &x){ char c=getchar(); while(c<'0'||c>'9')c=getchar(); for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');}struct TS{ int ch[2]; int key; pair<int,int> data;}treap[N];int root;int rand_32(){ return rand()<<17^rand()<<5^rand();}void out(TS node){ printf("{ch[0]=%d,ch[1]=%d,data=<%d,%d>}\n",node.ch[0],node.ch[1],node.data.first,node.data.second);}void outdfs(int node){ if(node){ printf("treap[%d]=",node); out(treap[node]); outdfs(treap[node].ch[0]); outdfs(treap[node].ch[1]); }}void rot(int node,int fa,bool dir){ treap[fa].ch[dir]=treap[node].ch[!dir]; treap[node].ch[!dir]=fa;}void add(int &node,int x){ if(node){ bool dir; if(treap[node].data<treap[x].data){ add(treap[node].ch[1],x); dir=1; } else{ add(treap[node].ch[0],x); dir=0; } if(treap[node].key>treap[x].key){ rot(x,node,dir); node=x; } } else node=x;}void del(int &node,int x){ if(node==x) if(treap[node].ch[0]||treap[node].ch[1]){ bool dir=treap[treap[node].ch[0]].key>treap[treap[node].ch[1]].key; rot(node=treap[node].ch[dir],x,dir); del(treap[node].ch[!dir],x); } else node=0; else if(treap[node].data<treap[x].data)del(treap[node].ch[1],x); else del(treap[node].ch[0],x);}int pred(int x){ int ans=0; for(int node=root;node;) if(treap[node].data>=treap[x].data)node=treap[node].ch[0]; else{ if(treap[node].data.first==treap[x].data.first)ans=treap[node].data.second; node=treap[node].ch[1]; } return ans;}int succ(int x){ int ans=n+1; for(int node=root;node;) if(treap[node].data<=treap[x].data)node=treap[node].ch[1]; else{ if(treap[node].data.first==treap[x].data.first)ans=treap[node].data.second; node=treap[node].ch[0]; } return ans;}struct SS{ int min,max; int gcd; int minsucc;}segt[N<<2];int gcd(int a,int b){ return b?gcd(b,a%b):a;}#define lson node<<1,l,l+r>>1#define rson node<<1|1,(l+r>>1)+1,rvoid out(SS node){ printf("{min=%d,max=%d,gcd=%d,minsucc=%d}\n",node.min,node.max,node.gcd,node.minsucc);}SS pushup(SS ls,SS rs,int l,int mid,int r){ return (SS){min(ls.min,rs.min),max(ls.max,rs.max),gcd(abs(a[mid+1]-a[mid]),gcd(ls.gcd,rs.gcd)),min(ls.minsucc,rs.minsucc)};}void build(int node,int l,int r){ if(l==r){ treap[l]=(TS){0,0,rand_32(),make_pair(a[l],l)}; add(root,l); segt[node]=(SS){a[l],a[l],0,succ(l)}; //outdfs(root); //puts(""); } else{ build(rson),build(lson); segt[node]=pushup(segt[node<<1],segt[node<<1|1],l,l+r>>1,r); } //printf("[%d,%d]=",l,r); //out(segt[node]);}void update(int node,int l,int r,int x,int y){ if(l==r){ del(root,x); a[x]=y; treap[x]=(TS){0,0,rand_32(),make_pair(y,x)}; add(root,x); segt[node]=(SS){y,y,0,succ(x)}; return; } else{ if(x<=l+r>>1)update(lson,x,y); else update(rson,x,y); segt[node]=pushup(segt[node<<1],segt[node<<1|1],l,l+r>>1,r); }}void pupdate(int node,int l,int r,int x){ if(l==r){ segt[node].minsucc=succ(x); return; } else{ if(x<=l+r>>1)pupdate(lson,x); else pupdate(rson,x); segt[node]=pushup(segt[node<<1],segt[node<<1|1],l,l+r>>1,r); }}SS query(int node,int l,int r,int L,int R){ //printf("query(%)") if(l==L&&r==R)return segt[node]; if(R<=l+r>>1)return query(lson,L,R); if(L>l+r>>1)return query(rson,L,R); return pushup(query(lson,L,l+r>>1),query(rson,(l+r>>1)+1,R),L,l+r>>1,R);}int main(){ freopen("bzoj_4373.in","r",stdin); //freopen("bzoj_4373.out","w",stdout); treap[0].key=0x7fffffff; int m; in(n),in(m); for(int i=1;i<=n;++i)in(a[i]); build(1,1,n); int op; int x,y; int l,r,k; int yescnt=0; SS ans; int pre; while(m--){ //printf("-----%d-----\n",m); in(op); if(op==1){ in(x),in(y); x^=yescnt,y^=yescnt; //printf("Update:%d=%d\n",x,y); pre=pred(x); update(1,1,n,x,y); if(pre)pupdate(1,1,n,pre); if(pre=pred(x))pupdate(1,1,n,pre); } else{ in(l),in(r),in(k); l^=yescnt,r^=yescnt,k^=yescnt; //printf("Query([%d,%d],%d)\n",l,r,k); ans=query(1,1,n,l,r); //printf("ans="); //out(ans); if(k?ans.gcd%k==0&&(ans.max-ans.min)/k==r-l&&ans.minsucc>r:ans.max==ans.min){ puts("Yes"); ++yescnt; } else puts("No"); } }}
代码(hash):
#include<cstdio>#include<iostream>using namespace std;#include<algorithm>#include<cstring>#include<cmath>const int N=3e5+5,M=3e5+5;char * cp=(char *)malloc(20000000);void in(int &x){ while(*cp<'0'||*cp>'9')++cp; for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0');}const int Z=1<<19;struct ZS{ int min; int sum;}zkw[Z<<1];void pushup(int node){ zkw[node]=(ZS){min(zkw[node<<1].min,zkw[node<<1|1].min),zkw[node<<1].sum+zkw[node<<1|1].sum};}const int inf=0x7fffffff;int main(){ freopen("bzoj_4373.in","r",stdin); freopen("bzoj_4373_hash.out","w",stdout); fread(cp,1,20000000,stdin); int n,m; in(n),in(m); for(int i=1;i<=n;++i){ in(zkw[Z+i].min); zkw[Z+i].sum=zkw[Z+i].min*zkw[Z+i].min*6; } for(int i=Z;--i;)pushup(i); int op; int x,y; int l,r,len,k; int yescnt=0; ZS ans; while(m--){ in(op); if(op==1){ in(x),in(y); x^=yescnt,y^=yescnt; zkw[x+=Z]=(ZS){y,y*y*6}; while(x>>=1)pushup(x); } else{ in(l),in(r),in(k); l^=yescnt,r^=yescnt,k^=yescnt; len=r-l; ans=(ZS){inf,0}; for(l+=Z-1,r+=Z+1;r-l>1;l>>=1,r>>=1){ if(~l&1){ //cout<<(l^1)-Z<<endl; ans.min=min(ans.min,zkw[l^1].min); ans.sum=ans.sum+zkw[l^1].sum; //cout<<"Get\n"; } if(r&1){ //cout<<(r^1)-Z<<endl; ans.min=min(ans.min,zkw[r^1].min); ans.sum=ans.sum+zkw[r^1].sum; //cout<<"Get\n"; } } //cout<<ans.min<<" "<<ans.sum<<endl; //cout<<(ans.min+ans.min+(r-l)*k)<<"*"<<(r-l+1)<<"->"<<((unsigned)((ans.min+ans.min+(r-l)*k)*(r-l+1))>>1)<<endl; //cout<<ans.min<<endl; //cout<<((unsigned)((ans.min+ans.min+len*k)*(len+1))>>1)<<endl; //cout<<(LL)ans.min*ans.min%Mod*(len+1)%Mod<<'+'<<(LL)len*(len+1)%Mod*ans.min%Mod*k%Mod<<'+'<<(LL)len*(len+1)%Mod*(len<<1|1)%Mod*pow(6,Mod-2)%Mod*k%Mod*k%Mod<<endl; if(ans.sum==ans.min*ans.min*(len+1)*6+len*(len+1)*ans.min*k*6+len*(len+1)*(len<<1|1)*k*k){ puts("Yes"); ++yescnt; } else puts("No"); } }}
总结:
①用引用写treap可以省去很多讨论。
②treap是可以不保存父指针的,这意味着一棵普通的treap也是可以可持久化的。(其实splay也是可以不保存父指针的,但是因为splay的时间复杂度是均摊的,所以它并不能可持久化。)
③判断两个子串是否相等?——hash!
- [bzoj4373]算术天才⑨与等差数列 解题报告
- 【BZOJ4373】算术天才⑨与等差数列
- [bzoj4373]算术天才⑨与等差数列
- BZOJ4373 算术天才⑨与等差数列
- 【bzoj4373】算术天才⑨与等差数列
- [bzoj4373]算术天才⑨与等差数列
- 【bzoj4373】算术天才⑨与等差数列
- bzoj4373 算术天才⑨与等差数列
- 线段树 bzoj4373 算术天才⑨与等差数列
- BZOJ4373: 算术天才⑨与等差数列 线段树
- [BZOJ4373][线段树]算术天才⑨与等差数列
- [BZOJ4373算术天才⑨与等差数列] 线段树
- 【线段树】BZOJ4373算术天才与等差数列
- 【线段树】BZOJ4373算术天才与等差数列
- bzoj 4373: 算术天才⑨与等差数列
- BZOJ 4373 算术天才⑨与等差数列
- bzoj 4373: 算术天才⑨与等差数列
- [bzoj] 4373算术天才⑨与等差数列
- [从头学数学] 第183节 周游列国拜诸侯(上)
- My eclisps里面,想运行一个类,却总是在运行另外一个包的类?
- 原码, 反码, 补码 详解
- 【bzoj3504】【cqoi2014】【危桥】【最大流】
- mysql性能优化的四个层次
- [bzoj4373]算术天才⑨与等差数列 解题报告
- js的左移右移计算
- ASP.NET 程序中常用的三十三种代码
- 第五章 会修电脑不会修收音机?—依赖倒转原则
- AsyncStorage尝试
- foreach的语句格式:for(元素类型t 元素变量x : 遍历对象obj)
- 计算机运算原理
- BestCoder Round #80小结
- MySQL索引原理及慢查询优化