1 条题解
-
0
自动搬运
来自洛谷,原作者为

donghanwen1225
一只啥都不会的蒟蒻搬运于
2025-08-24 22:38:17,当前版本为作者最后更新于2022-05-17 00:58:51,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
upd on :补充了一些证明。
SDOI 2022 D1T1。在考场上没有想出来小块对大块的做法,写了个 的暴力喜提 。
Part 1 : 考虑暴力该怎么做。
对于每次询问,首先我们将 和 的所有 按照顺序放到一起。令这些 组成的序列为 ,令 表示整个 序列中 的数量,容易得到 的长度为 。
那么题意可以转化为,找出一个区间 ,使得 $\sum\limits_{i=l}^{r}[a_{p_i}=x]=\sum\limits_{i=l}^{r}[a_{p_i}=y]$,并令 最大。
设当前考虑到了第 个数,在 序列的前 个数中有 个是 , 个是 ,当前的 数列的前缀和为 。令 ,可以发现,对两个相等的 ,区间 是一个满足题意的区间。
考虑维护当前每个 所对应的 的最小值 。那么在计算到 时,只需将答案与 比较取最大值即可。另外若 ,即 时,答案也可以直接更新为当前的前缀和。
时间复杂度为 。
Part 2 : 考虑根号平衡。
思考为什么上面的暴力无法通过此题。假设 序列是这样构成的:其中有 个 ,剩余 个全部不同。那么只要每次询问 ,时间复杂度就将达到 。
我们根据 大小是否达到 ,将数分为 “大块” 和 “小块” 两类。
下面分三类讨论:
1. 小块对小块。显然直接套用暴力即可。复杂度为 。
2. 大块对大块。因为大块的长度要超过 ,所以大块最多有 个。本质不同的询问数只有 种(对相同的询问,我们将答案用
unordered_map存下来,如果遇到相同的询问直接调用答案即可),直接套用暴力,这部分的复杂度最大为 。3. 小块对大块。现在我们不能将两部分直接拼起来了。
考虑利用小块的大小不超过 的性质。根据暴力的做法,我们将 序列中的数分为有效点和无效点两类。
显然,小块中每个点都是需要考虑在内的有效点。
然而大块中,许多点对答案是不可能产生贡献的。这是因为,选中的区间 中, 和 的数量必须相等,而大块因为点数多,而往往导致其远远压过小块,所以有很多点是无效点。
具体的,我们仍然考虑 序列,令 ,
设 中有一段极长的 连续子段,其长度为 ,这个连续子段的左右端点分别为 。那么, 序列中只有在 左侧和 右侧的 个 才可能成为有效点。这是因为,更多的 会压过 的个数。我们把这些点加入真正计算的 序列中。
另外注意,若 左侧 个 中间还包含了另外一些 的极长连续子段,则这些 子段向两侧拓展时要跳过这些已经成为有效点的 。这个过程可以使用
set去快速维护。得到有效点后将其离散化,再套用暴力即可。有效点的个数始终只与大小 的小块相关,所以是 级别的。
考虑到大块的数量不多,且复杂度取决于实际的小块长度,这部分的复杂度应当为 。虽然有效点个数带大常数,但从下面的复杂度分析来看,实际上还要带一个非常小的常数,整体来看常数较小。
大块对大块的复杂度较小直接忽略,总复杂度为 。由均值不等式,在 时,复杂度为 最优。这式子看起来好像能达到 ,不过因为跑不满 + 常数小,而且时限 ,所以是可以通过的。
按理论计算出来 左右最优,但由于数据非常离谱,实际上取 时间都差不多,但是取 的时候反而会 TLE。这样就通过了此题。
代码中为了简便,拓展 个有效点时直接是拓展了 个。
upd 1:补充大块对大块、小块对大块的复杂度的证明。
大块对大块:假设有 个大块,第 个的长度为 。极限情况下令 。
考虑令这 个大块两两配对进行询问,共进行 次询问。总计算次数为 $\sum\limits_{1\leq i<j\leq k}len_i+len_j=(k-1)\sum\limits_{i=1}^{k}len_i=n(k-1)$。
由于 ,得 ,故极限复杂度为 。
小块对大块:设有 个大块,第 个的长度为 ;有 个小块,第 个的长度为 。则有 $\sum\limits_{i=1}^{k_1}l_i+\sum\limits_{i=1}^{k_2}L_i=n$。
考虑到小块对大块的复杂度只取决于小块长度,我们用最长的 个小块对着大块进行询问。极限情况下,有 ,也即每个小块都对着每个大块查了一次。总计算次数为 $\sum\limits_{i=1}^{k_2}\sum\limits_{j=1}^{k_1}L_i\log l_j\leq k_1\log n\sum\limits_{i=1}^{k_2}L_i$。
最强的情况下,可构造 个长度略大于 的大块,和总长度大约为 的一些小块,此时 $k_1\approx\dfrac{n}{B},\sum\limits_{i=1}^{k_2}L_i\approx n$,故极限复杂度为 。此时要有 。
code:
#include<iostream> #include<cstdio> #include<set> #include<algorithm> #include<vector> #include<unordered_map> using namespace std; typedef long long ll; const int blo=300; int n,q,x,y,a[300005],len[300005],st[300005],tim[300005],pre[300005],cl[300005]; ll b[300005],mn[300005];unordered_map<int,ll> mp[300005];set<int> pos[300005]; struct node{int id;ll v;} xl[300005]; vector<node> tj[300005];vector<ll> qz[300005]; template<typename T> void Read(T &x) { x=0;bool f=0; char ch=getchar(); while(ch<'0'||ch>'9') f=f||(ch=='-'),ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar(); x=f==0?x:-x; } int main() { Read(n);Read(q); for(int i=1;i<=n;i++) Read(a[i]),tim[i]=tim[pre[a[i]]]+1,pre[a[i]]=i; for(int i=1;i<=n;i++) Read(b[i]); for(int i=1;i<=n;i++) tj[a[i]].push_back({i,b[i]}),pos[a[i]].insert(i); for(int i=1;i<=n;i++) if(tj[i].size()) { len[i]=tj[i].size();qz[i].resize(len[i]+1); for(int j=0;j<len[i];j++) qz[i][j+1]=qz[i][j]+tj[i][j].v; } for(int i=0;i<=n;i++) mn[i]=1ll<<60; while(q--) { Read(x);Read(y); if(mp[x].find(y)!=mp[x].end()){printf("%lld\n",mp[x][y]);continue;} if((len[x]>blo&&len[y]>blo)||(len[x]+len[y]<=blo)) { int tl=0,tr=0;ll ans=-(1ll<<60); while(tl<len[x]&&tr<len[y]) { if(tj[x][tl].id<tj[y][tr].id) xl[tl+tr]=tj[x][tl],tl++; else xl[tl+tr]=tj[y][tr],tr++; } while(tl<len[x]) xl[tl+tr]=tj[x][tl],tl++; while(tr<len[y]) xl[tl+tr]=tj[y][tr],tr++; int cur1=0,cur2=0; for(int i=0;i<len[x]+len[y];i++) { if(a[xl[i].id]==x) cur1++; if(a[xl[i].id]==y) cur2++; int sl=cur1-cur2+len[y]; if(sl==len[y]) ans=max(ans,qz[x][cur1]+qz[y][cur2]); ans=max(ans,qz[x][cur1]+qz[y][cur2]-mn[sl]); mn[sl]=min(mn[sl],qz[x][cur1]+qz[y][cur2]);cl[i]=sl; } mp[x][y]=mp[y][x]=ans;printf("%lld\n",ans); for(int i=0;i<len[x]+len[y];i++) mn[cl[i]]=1ll<<60; } else { if(len[x]>len[y]) swap(x,y); int top=0;ll ans=-(1ll<<60); for(int i=0;i<len[x];i++) { if(!pos[y].size()) continue; auto tmp=pos[y].lower_bound(tj[x][i].id); if(tmp==pos[y].begin()) continue;--tmp;st[++top]=*tmp; auto del=tmp;if(tmp==pos[y].begin()) continue;--tmp; st[++top]=*tmp;pos[y].erase(del);pos[y].erase(tmp); } for(int i=0;i<len[x];i++) { if(!pos[y].size()) continue; auto tmp=pos[y].upper_bound(tj[x][i].id); if(tmp==pos[y].end()) continue;st[++top]=*tmp; auto del=tmp;++tmp;if(tmp==pos[y].end()) continue; st[++top]=*tmp;pos[y].erase(del);pos[y].erase(tmp); } for(int i=1;i<=top;i++) pos[y].insert(st[i]); for(int i=0;i<len[x];i++) st[++top]=tj[x][i].id; sort(st+1,st+1+top);int cnt=unique(st+1,st+1+top)-st-1; for(int i=1;i<=cnt;i++) xl[i]={st[i],b[st[i]]}; int cur1=0,cur2=0,las1=0,las2=0; for(int i=1;i<=cnt;i++) { if(a[xl[i].id]==x) cur1+=tim[xl[i].id]-las1,las1=tim[xl[i].id]; if(a[xl[i].id]==y) cur2+=tim[xl[i].id]-las2,las2=tim[xl[i].id]; int sl=cur2-cur1+len[x]; if(sl==len[x]) ans=max(ans,qz[x][cur1]+qz[y][cur2]); ans=max(ans,qz[x][cur1]+qz[y][cur2]-mn[sl]); mn[sl]=min(mn[sl],qz[x][cur1]+qz[y][cur2]);cl[i]=sl; } mp[x][y]=mp[y][x]=ans;printf("%lld\n",ans); for(int i=1;i<=cnt;i++) mn[cl[i]]=1ll<<60; } } return 0; }
- 1
信息
- ID
- 7696
- 时间
- 7000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者