其他分享
首页 > 其他分享> > 题解【CF549F Yura and Developers】

题解【CF549F Yura and Developers】

作者:互联网

楼下的两篇题解都看不懂,不会笛卡尔树,不会打标找规律。

但是 $\texttt{CDQ}$ 分治你值得拥有。

对于分治的两个区间 $[l,mid]$ 和 $(mid,r]$,对于分别位于两个区间的点 $j,i$,计算是否有贡献。

设 $s_i$ 表示前缀/后缀和,$b_i$ 表示前缀/后缀最大值。

则可以将题目条件写成另一种形式:$s_j+s_i -\max (b_i,b_j)\equiv 0\pmod k$。

对于取 max 操作,我们最常见的手法就是分情况讨论。

这里只讨论 $b_j>b_i$ 的情况,另一种情况留给读者分析。

那么原式化为 $s_j+s_i -b_j\equiv 0\pmod k$。

令 $c_i =s_j -b_j$,则原式变为 $s_i+c_j \equiv 0\pmod k$。

那么本题可以转化为,对于 $b_j>b_i$ 的所有下标 $j$,有多少个满足与 $c_j+s_i\equiv 0\pmod k$。

这就很简单了,我们对 $[l,mid]$ 和 $(mid,r]$ 分别按照 $b_i$ 排序,然后一个 Two-Pointers 两边扫过去就行了。

单点修改单点查询的问题我竟然一开始 nt 写了树状数组然后被卡常了。

这样复杂度是 $\Theta(n\log^2 n)$,瓶颈在于排序。

能不能更快?

答案是可以的。

我们排序的 $b$ 是一个前缀/后缀最大值,它是具有单调性的,所以只需要区间反转,这是 $\Theta(n\log n)$ 的!

但你会发现不管是 $\Theta(n\log n)$ 还是 $\Theta(n\log ^2 n)$ 都是最劣解。

两次速度对比。

放一下代码(需要针对 $b$ 的大小关系做两次 $\texttt{CDQ}$,所以有点长):

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<cctype>
#include<stack>
#include<map>
#include<climits>
#include<set>
#include<iostream>
#define rint() read<int>()
#define rll() read<ll>()
#define rep(i,a,b) for(register int i=a;i<=b;++i)
#define rev(i,a,b) for(register int i=a;i>=b;--i)
#define gra(i,u) for(register int i=head[u];i;i=edge[i].nxt)
#define print(a,l,r) rep(i,l,r) printf("%d ",a[i]);
#define printll(a,l,r) rep(i,l,r) printf("%lld ",a[i]);
#define Clear(a) memset(a,0,sizeof(a))
#define yes puts("YES")
#define no puts("NO")
#define yyds puts("YYDS")
using namespace std;
typedef long long ll;
inline int read()
{
    register int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+(ch-'0'),ch=getchar();
    return s*w;
}
const int INF=1e9;
const ll LLINF=1e18;
template<typename T>
inline T Min(T x,T y){return x<y?x:y;}
template<typename T>
inline T Max(T x,T y){return x>y?x:y;}
template<typename T>
inline void Swap(T&x,T&y){int t=x;x=y;y=t;return;}
const int MAXN(3e5+10);
const int MAXM(1e6+10);
int n,k,a[MAXN],b[MAXN];
ll s[MAXN],c[MAXN]; 
struct Lsh{ll val,idx;};
Lsh lsh[MAXN];
inline bool cmp(Lsh x,Lsh y){return x.val<y.val;}
struct node{int s,c;int b;};
node h[MAXN];
inline bool cmp2(node x,node y){return x.b<y.b;}
inline bool cmp4(node x,node y){return x.b>y.b;}
inline void LSH(int l,int r)
{
    rep(i,l,r) lsh[i].idx=i,lsh[i].val=b[i];
    sort(lsh+l,lsh+r+1,cmp);
    int v(0);
    lsh[l-1].val=-1;
    rep(i,l,r) if(lsh[i].val!=lsh[i-1].val) b[lsh[i].idx]=++v;else b[lsh[i].idx]=v;
    return;
}

int bit[MAXM];
inline ll CDQ(int l,int r)
{
    if(l==r) return 0;
    int mid=(l+r)>>1;
    ll ans=CDQ(l,mid)+CDQ(mid+1,r);
    
    b[mid]=a[mid],s[mid]=a[mid],b[mid+1]=a[mid+1],s[mid+1]=a[mid+1];
    
    rev(i,mid-1,l) b[i]=Max(a[i],b[i+1]),s[i]=s[i+1]+(ll)a[i];
    rep(i,mid+2,r) b[i]=Max(a[i],b[i-1]),s[i]=s[i-1]+(ll)a[i];
    rep(i,l,r) c[i]=s[i]-(ll)b[i];
    rep(i,l,r)
    {
        c[i]%=k,s[i]=(-s[i]%k+(ll)k)%k;
        h[i].c=(int)c[i]+1,h[i].s=(int)s[i]+1,h[i].b=b[i];
    } 
    reverse(h+l,h+mid+1);
    int j(l);
    rep(i,mid+1,r)
    {
        while(j<=mid&&h[j].b<h[i].b) ++bit[h[j].s],++j;
        ans+=(ll)bit[h[i].c];
    }
    rep(i,l,j-1) --bit[h[i].s];
    return ans;
}
inline ll CDQ2(int l,int r)
{
    if(l==r) return 0;
    int mid=(l+r)>>1;
    ll ans=CDQ2(l,mid)+CDQ2(mid+1,r);
    b[mid]=a[mid],s[mid]=a[mid];
    b[mid+1]=a[mid+1],s[mid+1]=a[mid+1];
    rev(i,mid-1,l) b[i]=Max(a[i],b[i+1]),s[i]=s[i+1]+(ll)a[i];
    rep(i,mid+2,r) b[i]=Max(a[i],b[i-1]),s[i]=s[i-1]+(ll)a[i];
    rep(i,l,r)
    {
        c[i]=((b[i]-s[i])%k+(ll)k)%k,s[i]%=k;
        h[i].c=(int)c[i]+1,h[i].s=(int)s[i]+1,h[i].b=b[i];
    } 
    reverse(h+mid+1,h+r+1);
    int j(l);
    rep(i,mid+1,r)
    {
        while(j<=mid&&h[j].b>=h[i].b) ++bit[h[j].c],++j;
        ans+=bit[h[i].s];
    }
    rep(i,l,j-1) --bit[h[i].c];
    return ans;
}
int main()
{
//    freopen("read.txt","r",stdin);
    n=read(),k=read();
    rep(i,1,n) a[i]=read();
    printf("%lld\n",CDQ(1,n)+CDQ2(1,n));
    return 0;
}
/*
4 3
1 2 3 4
//3

4 2
4 4 7 4
//6

5 6
3 3 12 8 10
//3
*/ 

标签:include,ll,int,题解,rep,mid,lsh,Developers,Yura
来源: https://www.cnblogs.com/UperFicial/p/16377512.html