T1:BZOJ 4013 xor
题目大意:给定一个长度为 n 的数列 a 和一个长度为 m 的数列 b ,给定矩阵 A ,令 Ai,j=ai⊕bj , q 次询问某个子矩形里的 k 大值
n≤1000,m≤3∗105,q≤500
刚看到这题的时候我发现我不会,看到数据范围的时候我发现出题人也不会……
如果 n=1 ,那么我们对这 m 个数建立可持久化Trie树,每次询问的时候查询异或 a1 的 k 大值即可
那么现在 n=1000 ,我们只需要把这 2000 棵Trie树放在一起跑即可
时间复杂度 O(m∗32+n∗q∗32)
二分答案会T掉。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
struct Trie{
Trie *son[2];
int val;
void* operator new (size_t,Trie *_,Trie *__,int ___)
{
static Trie *mempool,*C=mempool;
if(C==mempool)
mempool=(C=new Trie[1<<15])+(1<<15);
C->son[0]=_;
C->son[1]=__;
C->val=___;
return C++;
}
friend Trie* Insert(Trie *p,int x,int digit)
{
if(!digit)
return new (p->son[0],p->son[1],p->val+1)Trie;
if(x&digit)
return new (p->son[0],Insert(p->son[1],x,digit>>1),p->val+1)Trie;
else
return new (Insert(p->son[0],x,digit>>1),p->son[1],p->val+1)Trie;
}
friend int Get_Kth(Trie *stack1[],Trie *stack2[],int stack3[],int top,int digit,int k)
{
int i,temp=0;
if(!digit)
return 0;
for(i=1;i<=top;i++)
{
temp+=stack1[i]->son[stack3[i]&digit?0:1]->val;
temp-=stack2[i]->son[stack3[i]&digit?0:1]->val;
}
if(k<=temp)
{
for(i=1;i<=top;i++)
{
stack1[i]=stack1[i]->son[stack3[i]&digit?0:1];
stack2[i]=stack2[i]->son[stack3[i]&digit?0:1];
}
return digit|Get_Kth(stack1,stack2,stack3,top,digit>>1,k);
}
else
{
for(i=1;i<=top;i++)
{
stack1[i]=stack1[i]->son[stack3[i]&digit?1:0];
stack2[i]=stack2[i]->son[stack3[i]&digit?1:0];
}
return Get_Kth(stack1,stack2,stack3,top,digit>>1,k-temp);
}
}
}*tree[M];
int n,m,q;
int a[1010],b[M];
Trie *stack1[1010],*stack2[1010];
int stack3[1010],top;
int main()
{
int i,k,l1,r1,l2,r2;
cin>>n>>m;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=m;i++)
scanf("%d",&b[i]);
tree[0]=new (0x0,0x0,0)Trie;
tree[0]->son[0]=tree[0]->son[1]=tree[0];
for(i=1;i<=m;i++)
tree[i]=Insert(tree[i-1],b[i],1<<30);
for(cin>>q;q;q--)
{
scanf("%d%d%d%d%d",&l1,&r1,&l2,&r2,&k);
top=0;
for(i=l1;i<=r1;i++)
{
stack1[++top]=tree[r2];
stack2[ top]=tree[l2-1];
stack3[ top]=a[i];
}
printf("%d\n",Get_Kth(stack1,stack2,stack3,top,1<<30,k));
}
return 0;
}
T2:BZOJ 4015 square
题目大意:维护一个序列,支持两种操作:
1.将区间的每个数 x 改为 x2 mod p
2.求区间和(不取模)
观察题目中给的模数,我们可以打个表,发现任何一个数到环的距离不超过 11 ,而且所有环长的 Lcm 不超过 60
然后就是花神的游览计划了……
对于不在环上的节点我们暴力修改 对于所有节点都在环上的区间直接用一个链表维护这个环 然后区间求平方的时候向前走一位就行了
时间复杂度 O(nlogn∗60)
似乎这个题过的人很少?
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,m,p;
int v[M],on_ring[M],T;
struct List{
int val;
List *next;
friend List* Merge(List *r2,List *r3,int len)
{
int i;
List *head=new List,*r1=head;
r1->val=r2->val+r3->val;
for(i=2;i<=len;i++)
{
r1->next=new List;
r1=r1->next;
r2=r2->next;
r3=r3->next;
r1->val=r2->val+r3->val;
}
return r1->next=head;
}
friend void Merge(List *r1,List *r2,List *r3,int len)
{
int i;
for(i=1;i<=len;i++)
{
r1->val=r2->val+r3->val;
r1=r1->next;
r2=r2->next;
r3=r3->next;
}
}
};
List* Get_Ring(int x,int &len)
{
List *head=new List,*last=head;
int i;
head->val=x;len=1;
for(i=x*x%p;i!=x;i=i*i%p)
{
last->next=new List;
last=last->next;
last->val=i;len++;
}
return last->next=head;
}
struct Segtree{
Segtree *ls,*rs;
int sum,len,mark;
List *ring;
void* operator new (size_t)
{
static Segtree mempool[M<<1],*C=mempool;
return C++;
}
void Rotate(int x)
{
mark+=x;
for(x%=len;x;x--)
ring=ring->next;
sum=ring->val;
}
void Push_Up()
{
if(!len&&ls->len&&rs->len)
{
len=ls->len*rs->len/__gcd(ls->len,rs->len);
ring=Merge(ls->ring,rs->ring,len);
}
sum=ls->sum+rs->sum;
Merge(ring,ls->ring,rs->ring,len);
}
void Push_Down()
{
if(mark)
{
ls->Rotate(mark);
rs->Rotate(mark);
mark=0;
}
}
void Build_Tree(int x,int y,int a[])
{
int mid=x+y>>1;
if(x==y)
{
sum=a[mid];
if(on_ring[sum])
ring=Get_Ring(sum,len);
return ;
}
(ls=new Segtree)->Build_Tree(x,mid,a);
(rs=new Segtree)->Build_Tree(mid+1,y,a);
Push_Up();
}
void Modify(int x,int y,int l,int r)
{
int mid=x+y>>1;
if(x==l&&y==r)
{
if(len)
Rotate(1);
else if(x==y)
{
sum=sum*sum%p;
if(on_ring[sum])
ring=Get_Ring(sum,len);
}
else
{
ls->Modify(x,mid,l,mid);
rs->Modify(mid+1,y,mid+1,r);
Push_Up();
}
return ;
}
Push_Down();
if(r<=mid)
ls->Modify(x,mid,l,r);
else if(l>mid)
rs->Modify(mid+1,y,l,r);
else
ls->Modify(x,mid,l,mid) , rs->Modify(mid+1,y,mid+1,r) ;
Push_Up();
}
int Get_Ans(int x,int y,int l,int r)
{
int mid=x+y>>1;
if(x==l&&y==r)
return sum;
Push_Down();
if(r<=mid)
return ls->Get_Ans(x,mid,l,r);
if(l>mid)
return rs->Get_Ans(mid+1,y,l,r);
return ls->Get_Ans(x,mid,l,mid) + rs->Get_Ans(mid+1,y,mid+1,r) ;
}
}*tree=new Segtree;
void DFS(int x)
{
if(v[x])
{
if(v[x]!=T)
return ;
int i=x;
do{
on_ring[i]=true;
i=i*i%p;
}while(i!=x);
return ;
}
v[x]=T;
DFS(x*x%p);
}
int main()
{
#ifdef PoPoQQQ
freopen("4105.in","r",stdin);
freopen("4105.out","w",stdout);
#endif
static int a[M];
int i,op,x,y;
cin>>n>>m>>p;
for(i=0;i<p;i++)
if(!v[i])
++T,DFS(i);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
tree->Build_Tree(1,n,a);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&x,&y);
if(op==0)
tree->Modify(1,n,x,y);
else
printf("%d\n",tree->Get_Ans(1,n,x,y));
}
return 0;
}
T3:BZOJ 4014 decipher
题目大意:给定一个字符串,将这个字符串后面加一个’.’,然后将所有与这个字符串环同构的串排个序,把最后一列给你,要求输出原串
傻逼题放在T3已经成为了一种传统了么=- -=
看代码对着样例多理解理解吧这题实在说不明白
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
int n,m;
int a[M],b[M],c[M],d[M],ans[M];
bool Compare(int x,int y)
{
if(a[x]!=a[y])
return a[x]<a[y];
if(b[x]!=b[y])
return b[x]<b[y];
return x<y;
}
int main()
{
int i;
cin>>n>>m;
for(i=1;i<=n+1;i++)
scanf("%d",&a[i]);
for(i=1;i<=n+1;i++)
b[i]=a[i];
sort(b+1,b+n+2);
for(i=1;i<=n+1;i++)
c[i]=i;
sort(c+1,c+n+2,Compare);
for(i=1;i<=n+1;i++)
d[c[i]]=i;
int pos=1;
for(i=n;i;i--)
{
ans[i]=a[pos];
pos=d[pos];
}
for(i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}