20190307
T1
小b有一个 $01$ 串。
小b发现实数 $f$ 很美,因此她想请你找出一个子串,使得子串中 $1$ 的个数除以子串长度跟 $f$ 尽可能的接近。
输出这个子串的左端点(从 $0$ 开始标号)。如果有多个可能的子串,输出左端点最小的那个。
$1≤n≤100000$
题解
场上想出正解写飞了 $QwQ$
考虑转化为二维平面上的点,先往右走一格,如果是 $1$ 就往上一格
这样我们可以得到 $n+1$ 个点( $(0,0)$ 也算),那我们把斜率为 $f$ 的直线放在每个点上,会产生 $n+1$ 个截距,截距最相近的就是要找的那一段字符串
效率 $O(nlogn)$ (需要排序)
T2
内存限制:512 MiB
时间限制:1500 ms
Luka非常擅长解决汉诺塔问题,他发明了一种类似汉诺塔的使用盘子和柱子的游戏。这个游戏有 $n$ 个不同大小的盘子以及 $36$ 根柱子。盘子按照大小从小到大依次被编号为 $1$ 到 $n$ 。柱子形成了 $6$ 行 $6$ 列的矩阵,从上到下每行依次被编号为 $1$ 到 $6$ ,从左到右每列依次被编号为 $1$ 到 $6$。
游戏一开始,$n$ 个盘子都被堆叠在左上角坐标为 $(1,1)$ 的柱子上。对于每一次操作,玩家可以选择一个柱子,取出最顶上若干个盘子,然后选择右边或者下面的某个柱子,将取出的盘子全部堆叠在其顶上(不会翻转顺序)。游戏的目标是把所有盘子都移动到 $(6,6)$ ,且自底向上大小依次递减。
给定游戏的初始局面,请找到任意一组玩通关的方法。数据保证解必定存在。
$1≤n≤40000$
题解
orzjarden
$(1,1)$ 因为没有移动,所以只能保证顶部第一个棋子是有序的,$(2,1)(1,2)$ 可以通过比较 $(1,1)$ 的顶部两个棋子来做到两个棋子的有序
剩下的格子可以通过在它左上方的个子的有序的数量来确定这个格子的有序,递归处理就可以了。
效率 $O(jarden)$ (不会算效率
T3
内存限制:256 MiB
时间限制:2000 ms
火星上的一条商业街里按照商店的编号 $1,2,3,…,n$ ,依次排列着 $n$ 个商店。商店里出售的琳琅满目的商品中,每种商品都用一个非负整数 $val$ 来标价。每个商店每天都有可能进一些新商品,其标价可能与已有商品相同。
火星人在这条商业街购物时,通常会逛这条商业街某一段路上的所有商店,譬如说商店编号在区间 $[L,R]$ 中的商店,从中挑选 $1$ 件自己最喜欢的商品。每个火星人对商品的喜好标准各不相同。通常每个火星人都有一个自己的喜好密码 $x$ 。对每种标价为 $val$ 的商品,喜好密码为 $x$ 的火星人对这种商品的喜好程度与 $val$ 异或 $x$ 的值成正比。也就是说, $val \oplus x$ 的值越大,他就越喜欢该商品。每个火星人的购物卡在所有商店中只能购买最近 $d$ 天内(含当天)进货的商品。另外,每个商店都有一种特殊商品不受进货日期限制,每位火星人在任何时刻都可以选择该特殊商品。每个商店中每种商品都能保证供应,不存在商品缺货的问题。
对于给定的按时间顺序排列的事件,计算每个购物的火星人的在本次购物活动中最喜欢的商品,即输出 val⊕xval \oplus xval⊕x 的最大值。这里所说的按时间顺序排列的事件是指以下 2 种事件:
事件 0 ,用 3 个整数 $0,s,v$ ,表示编号为 $s$ 的商店在当日新进一种标价为 $v$ 的商品。
事件 1,用 5 个整数 $1,L,R,x,d$ ,表示一位火星人当日在编号为 $L$ 到 $R$ 的商店购买 $d$ 天内的商品,该火星人的喜好密码为 $x$。
(补充说明:每个事件 0 代表新一天的开始。每个事件 1 和其之前的最后一个事件 0 同一天,如果没有当做第 0 天。第一个事件 0 代表第 1 天的开始。)
$1\leq n,m,x,val\leq 100000$
题解
暴力可以写树套树,可惜这样内存是开不下的,只能拿到 60~80 分
发现了一种新的神奇的分治方法:线段树分治
我们对于时间天数开一棵线段树,然后对于一个在 $t_i$ 天的事件 1 ,它可以购买 $d_i$ 天内的商品,这个时候我们将这个询问插入这个线段树中,覆盖的范围是 $[t_i-d_i+1,t_i]$
先考虑事件 0 为事件 1 所造成的贡献
我们开始对事件 0 按照加入商店的编号排序,接着遍历这一棵线段树,进行分治
到了一个节点,我们有一些事件 0 ,这些事件 0 有可能对这个区间的询问造成影响,所以我们在这个节点上对这一些事件 0 按照商品编号开一棵可持久化 $trie$ 树,接着每个询问在 $trie$ 树上寻找答案即可
由于每到一个节点,$trie$ 树都是重新建立的,所以这样内存可以保证
对于一些特殊的商品,只需要在一开始的时候建立可持久化 $trie$ 树,在输入的时候即可找到答案
效率 $O(nlog^2n)$
献上代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,tt,tn,T[N],xw,tp,S[N],ans[N];
struct Trie{int son[2],s;}t[N*20];
struct Add{int s,v,d;}q[N],hl[N],hr[N];
struct Ask{int ql,qr,tl,tr,v;}p[N];
bool cmp(Add A,Add B){return A.s<B.s;}
vector<int>g[N*4];
void ins(int& x,int y,int v,int d){
t[x=++tt]=t[y];t[x].s++;
if (!~d) return;bool g=(v>>d)&1;
ins(t[x].son[g],t[y].son[g],v,d-1);
}
int find(int x,int y,int v,int d){
if (!~d) return 0;bool g=(v>>d)&1;
if (t[t[x].son[!g]].s-t[t[y].son[!g]].s)
return (1<<d)+find(t[x].son[!g],t[y].son[!g],v,d-1);
return find(t[x].son[g],t[y].son[g],v,d-1);
}
#define Ls k<<1
#define Rs k<<1|1
#define mid ((l+r)>>1)
void update(int k,int l,int r,int L,int R,int v){
if (L<=l && r<=R){g[k].push_back(v);return;}
if (mid>=L) update(Ls,l,mid,L,R,v);
if (mid<R) update(Rs,mid+1,r,L,R,v);
}
void calc(int k,int L,int R){
tp=tt=0;
for (int i=L;i<=R;i++)
S[++tp]=q[i].s,ins(T[tp],T[tp-1],q[i].v,17);
for (int j,i=g[k].size()-1;~i;i--){
j=g[k][i];
int l=upper_bound(S+1,S+tp+1,p[j].ql-1)-S-1;
int r=upper_bound(S+1,S+tp+1,p[j].qr)-S-1;
ans[j]=max(ans[j],find(T[r],T[l],p[j].v,17));
}
}
void solve(int k,int l,int r,int L,int R){
int cl=0,cr=0;calc(k,L,R);
if (l==r) return;
for (int i=L;i<=R;i++)
if (q[i].d<=mid) hl[++cl]=q[i];
else hr[++cr]=q[i];
for (int i=1;i<=cl;i++) q[L+i-1]=hl[i];
for (int i=1;i<=cr;i++) q[L+cl+i-1]=hr[i];
if (cl) solve(Ls,l,mid,L,L+cl-1);
if (cr) solve(Rs,mid+1,r,L+cl,R);
}
int main(){
scanf("%d%d",&n,&m);
for (int x,i=1;i<=n;i++)
scanf("%d",&x),ins(T[i],T[i-1],x,17);
for (int op,L,R,x,y;m--;){
scanf("%d",&op);
if (op)
scanf("%d%d%d%d",&L,&R,&x,&y),
ans[++xw]=find(T[R],T[L-1],x,17),
p[xw]=(Ask){L,R,tn-y+1,tn,x};
else
scanf("%d%d",&x,&y),tn++,
q[tn]=(Add){x,y,tn};
}
for (int i=1;i<=xw;i++) if (p[i].tl<=p[i].tr)
update(1,1,tn,p[i].tl,p[i].tr,i);
sort(q+1,q+tn+1,cmp);solve(1,1,tn,1,tn);
for (int i=1;i<=xw;i++) printf("%d\n",ans[i]);
return 0;
}