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

Wind_Leaves_ShaDow
别摆了。搬运于
2025-08-24 23:01:57,当前版本为作者最后更新于2025-02-05 16:00:06,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
社贡快掉没了来写篇题解/kk。
题意
你需要把一个序列分成至多 段,定义每一段 的花费为其中数对 的个数,满足 且 。其中 是给定的常数。
问最小花费。。
题解
设 表示前 个数分成 段最小花费。转移为 。其中 即为 分为一段的花费。
观察发现这个式子很能够决策单调性优化,可以证明其 满足四边形不等式。如果需要的话证明在代码后面。
然后很好做了,分治每一层得到答案,这里不多赘述。
思考一下没有什么数据结构支持快速得到 的值,于是自然而然地想到类似莫队移动指针的维护方式。移动指针的复杂度是 的,证明考虑刻画指针移动路径,每一层指针只会在候选区间进行线性次数的移动,而分治一共是 层。
考虑令位置 的前缀异或和为 ,则一次查询变成询问 且 的 个数。这个很容易统计出来,开两个桶记录 的集合和 的集合。注意移动指针时的删除添加顺序。
于是做完了,一共有 层每层做一次分治,复杂度 。
没有仔细想,但是感觉如果 大一点是不是可以套上 wqs 二分做到 ?
注意到 不代表桶的上界是 。
代码
#include <bits/stdc++.h> #define lint __int128 #define int long long #define fi first #define se second #define Rg register #define Ri Rg int #define Il inline #define vec vector #define pb push_back #define IT ::iterator #define p_que priority_queue using namespace std; typedef long long ll; typedef double db; typedef pair<int,int> pii; const int N=1e5,M=(1<<20),Inf=1e18; const db eps=1e-9,pi=acos(-1.0); Il int read(){ int x=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;'0'<=ch&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return x*f; } Il void write(ll x){ if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+48); return; } int n,m,K,a[N+5],dp[N+5][25],lp=1,rp=0,ans=0,gl[M+5],gr[M+5]; Il void adl(int p){gr[a[p]]++;ans+=gr[K^a[p-1]];gl[a[p-1]]++;return;} Il void del(int p){ans-=gr[K^a[p-1]];gr[a[p]]--;gl[a[p-1]]--;return;} Il void adr(int p){gl[a[p-1]]++;ans+=gl[K^a[p]];gr[a[p]]++;return;} Il void der(int p){ans-=gl[K^a[p]];gl[a[p-1]]--;gr[a[p]]--;return;} Il int qur(int l,int r){ while(lp>l)adl(--lp); while(lp<l)del(lp++); while(rp<r)adr(++rp); while(rp>r)der(rp--); return ans; } Il void solve(int l,int r,int zl,int zr,int ly){ int mid=(l+r)>>1,p=zl;if(l>r||zl>zr)return; dp[mid][ly]=Inf; for(Ri i=zl;i<=min(mid,zr);i++){ int tmp=dp[i-1][ly-1]+qur(i,mid); if(tmp<dp[mid][ly])dp[mid][ly]=tmp,p=i; } solve(l,mid-1,zl,p,ly),solve(mid+1,r,p,zr,ly); return; } signed main(){ n=read(),m=read(),K=read();for(Ri i=1;i<=n;i++)a[i]=read(); for(Ri i=1;i<=n;i++)a[i]^=a[i-1],dp[i][0]=Inf; for(Ri i=1;i<=m;i++)solve(1,n,1,n,i); ans=Inf;for(Ri i=1;i<=m;i++)ans=min(ans,dp[n][i]); cout<<ans; return 0; }证明满足四边形不等式
设有 。
我们的权值函数统计的是类似一种合法点对的答案,考虑对应到坐标系中, 统计的实际上就是以 为对角线的矩形中合法点对数(这里除对角线上每个点对会被算两次,但是并不影响证明)。
于是将 对应到坐标系,发现前者比后者多覆盖了以 和 为对角线的两个小矩形。
显然就有 ,得证。
- 1
信息
- ID
- 10616
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者