THUSC2015

来源:互联网 发布:linux 查看cpu几核 编辑:程序博客网 时间:2024/06/07 05:32

这套题测得时候被暴虐了。。。


T1:  bzoj 4103: [Thu Summer Camp 2015]异或运算  http://www.lydsy.com/JudgeOnline/problem.php?id=4103 

这题是个水题,就是以Y数列建trie,然后对于每个询问,都枚举每个X去trie上跑,就OK了,复杂度O(nplog value)

#include<cmath>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>using namespace std;const int maxn=1011,maxm=300011;inline int read(){int x=0; char ch=getchar();while (!isdigit(ch)) ch=getchar();for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0';return x;}int n,m,a[maxn],b[maxm];void init(){n=read(); m=read();for (int i=1;i<=n;++i) a[i]=read();for (int i=1;i<=m;++i) b[i]=read();}struct Ttrie{struct node{node *c[2]; int sum;}*null,e[12000000],*root[maxm];int tot;void clear(node &x){x.c[0]=x.c[1]=null; x.sum=0;}node *newnode(){clear(e[++tot]); return &e[tot];}void clear(){tot=0; null=e; null->c[0]=null->c[1]=null; null->sum=0;root[0]=newnode();}void ins(int w,int x){node *p=root[w]=newnode(),*lp=root[w-1];for (int i=30;i>=0;--i){bool s=(bool)((1<<i)&x);*p=*lp; ++p->sum; p->c[s]=newnode();p=p->c[s]; lp=lp->c[s];}*p=*lp; ++p->sum;}}t;void prepare(){t.clear();for (int i=1;i<=m;++i) t.ins(i,b[i]);}struct Tq{int a,b,v;Tq(){}Tq(int a_,int b_,int v_):a(a_),b(b_),v(v_){}};int getans(int u,int d,int l,int r,int rank){static Tq q[maxn<<1]; int cnt=0,res=0;for (int i=u;i<=d;++i) q[++cnt]=Tq(i,l-1,-1);for (int i=u;i<=d;++i) q[++cnt]=Tq(i,r,1);static Ttrie::node *w[maxn<<1];for (int i=1;i<=cnt;++i) w[i]=t.root[q[i].b];for (int t=30;t>=0;--t){int sum=0;for (int i=1;i<=cnt;++i)sum+=q[i].v*w[i]->c[!(bool)((1<<t)&a[q[i].a])]->sum;if (sum<rank){rank-=sum;for (int i=1;i<=cnt;++i) w[i]=w[i]->c[(bool)((1<<t)&a[q[i].a])];}else{res+=1<<t;for (int i=1;i<=cnt;++i) w[i]=w[i]->c[!(bool)((1<<t)&a[q[i].a])];}}return res;}void work(){prepare(); int Q=read();while (Q--){int a=read(),b=read(),l=read(),r=read(),rank=read();printf("%d\n",getans(a,b,l,r,rank));}}int main(){freopen("xor.in","r",stdin); freopen("xor.out","w",stdout);init(); work();fclose(stdin); fclose(stdout);return 0;}


T2:  bzoj 4105: [Thu Summer Camp 2015]平方运算  http://www.lydsy.com/JudgeOnline/problem.php?id=4105

这题非常神,深度膜拜了 http://blog.csdn.net/PoPoQQQ/article/details/46349249 之后,仍然什么都不懂,最后找PoPoQQQ问了一下,终于弄懂了  Orz

这题我们容易发现在平方时是有环的,然后发现给你的p的环长的lcm最大是60,到环的距离最大为11

于是我们维护一棵seg,每个节点有两种转态1:有点不在环上 2:所有点都在环上

第2种就在节点上维护一个链表,因为环的lcm<=60,所以链表长60就行了,update的时候把两个儿子的链表合并就是O(60nlogn)的

问题就在于第1种,如果在修改的时候碰到了第1种节点怎么打标记呢,大神给我的答案就是直接修改两个儿子,然后向上更新,这样的复杂度在一起最多是O(11nlogn)的(因为到环的距离不超过11),
于是这样复杂度就是O(60nlogn)的了

#include<cmath>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>using namespace std;const int maxn=100011,maxmod=10011,maxc=63;int n,m,mod,a[maxn];void init(){scanf("%d%d%d",&n,&m,&mod);for (int i=1;i<=n;++i) scanf("%d",a+i);}int next[maxmod]; bool Incir[maxmod];void prepare(){static bool vis[maxmod]; memset(Incir,1,sizeof(Incir));for (int i=0;i<mod;++i) next[i]=(i*i)%mod;for (int i=0;i<mod;++i) if (!vis[i]){int y=i,x=0; while (!vis[y]) vis[y]=1,y=next[y],++x;if (y!=i) for (int t=i;t!=y;t=next[t]) Incir[t]=0;}}inline int lcm(int &a,int &b){return a/__gcd(a,b)*b;}struct Tseg{struct node{int sum,w,len,cov,cir[maxc]; bool Ici;void init(int v){sum=v; Ici=Incir[v];if (Ici){len=1; cir[w=0]=v;for (int x=next[v];x!=v;x=next[x]) cir[len++]=x;}}}e[maxn<<2];void update(int p){node *x=e+p,*l=e+(p<<1),*r=l+1;x->sum=l->sum+r->sum; x->Ici=l->Ici&r->Ici;if (x->Ici){x->len=lcm(l->len,r->len); int tx=l->w,ty=r->w;for (int i=0;i<x->len;++i){x->cir[i]=l->cir[tx]+r->cir[ty];++tx; ++ty; if (tx==l->len) tx=0; if (ty==r->len) ty=0;}x->w=0;}}void pushdown(int p){if (!e[p].cov) return;node *x=e+p,*l=e+(p<<1),*r=l+1;int c=x->cov; x->cov=0; l->cov+=c; r->cov+=c;l->w+=c; if (l->w>=l->len) l->w%=l->len; l->sum=l->cir[l->w];r->w+=c; if (r->w>=r->len) r->w%=r->len; r->sum=r->cir[r->w];}void build(int p,int l,int r){if (l==r){e[p].init(a[l]); return;}int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r);update(p);}void clear(){build(1,1,n);}void modify(int p,int l,int r,int fir,int las){if (l==fir && r==las && e[p].Ici){++e[p].cov; ++e[p].w; if (e[p].w==e[p].len) e[p].w=0;e[p].sum=e[p].cir[e[p].w]; return;}if (l==r){e[p].init(next[e[p].sum]); return;}pushdown(p); int mid=(l+r)>>1;if (las<=mid) modify(p<<1,l,mid,fir,las);else if (fir>mid) modify(p<<1|1,mid+1,r,fir,las);else modify(p<<1,l,mid,fir,mid),modify(p<<1|1,mid+1,r,mid+1,las);update(p);}int Query(int p,int l,int r,int fir,int las){if (l==fir && r==las) return e[p].sum;pushdown(p); int mid=(l+r)>>1;if (las<=mid) return Query(p<<1,l,mid,fir,las);if (fir>mid) return Query(p<<1|1,mid+1,r,fir,las);return Query(p<<1,l,mid,fir,mid)+Query(p<<1|1,mid+1,r,mid+1,las);}void modify(int l,int r){modify(1,1,n,l,r);}int Query(int l,int r){return Query(1,1,n,l,r);}}seg;void work(){prepare(); seg.clear();while (m--){int op,l,r; scanf("%d%d%d",&op,&l,&r);if (op) printf("%d\n",seg.Query(l,r));else seg.modify(l,r);}}int main(){init();work();return 0;}

T3:  bzoj 4104: [Thu Summer Camp 2015]解密运算   http://www.lydsy.com/JudgeOnline/problem.php?id=4104

这题标程非常短,但就是不明觉厉,膜拜了PPS大神后弄懂了

首先如果各不相同那就非常水了,因为最左边一列就是最右边一列排序后的。问题就在于如果有相同的不知道谁是谁了,然而可以发现在左边以x开头的对应到右边来以x结尾的相对顺序是不会变的,于是又可以找到对应关系了,这样就很水了

#include<cmath>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>using namespace std;const int maxn=200011;int now=0,n,a[maxn];void init(){scanf("%d%*d",&n); ++n;for (int i=1;i<=n;++i){scanf("%d",a+i);if (!a[i]) now=i;}}struct Tp{int v,pos;Tp(){}Tp(int v_,int pos_):v(v_),pos(pos_){}}q[maxn];inline bool cmp(Tp a,Tp b){return a.v<b.v || a.v==b.v && a.pos<b.pos;}void work(){for (int i=1;i<=n;++i) q[i]=Tp(a[i],i);sort(q+1,q+n+1,cmp);for (int i=1;i<n;++i){printf("%d ",a[q[now].pos]); now=q[now].pos;}}int main(){init();work();return 0;}


0 0
原创粉丝点击