GYM 102439 Equal Mod Segments

该博客探讨了一个数学问题:给定序列,找出满足条件的区间[l, r],使得a[l]%a[l+1]%...%a[r]==a[r]%a[r-1]%...%a[l]。通过分析,提出以区间最小值为中心,递归处理左右子区间,并使用set维护向左和向右取模的状态,最后统计合法区间。采用启发式分治策略,确保算法复杂度为nloglogn。" 93369744,8317915,Qt编程:QSettings实现.ini配置文件操作指南,"['Qt开发', '配置文件处理', 'QSettings使用']
部署运行你感兴趣的模型镜像

题意是,给你一个序列,问有多少区间 [l,r] 满足 a[l]%a[l+1]%a[l+2].....%a[r]==a[r]%a[r-1]%a[r-2]...%a[l]?

我们考虑一个区间 [l,r] 假设区间内最小值在pos处取得,那么区间的合法性可以表示为

a[l]%a[l+1]%a[l+2].....%a[pos]==a[r]%a[r-1]%a[r-2]...%a[pos].因为在mod a[pos]之后,值是小于apos的,继续取余比较大的数也没有什么意义。

如果pos==l || pos==r 呢?如果区间内没有等于apos的数,那么区间一定是不合法的。只有区间内有多个等于apos的数才有可能合法,这里需要特判一下。

所以只要统计一个每个最小值左右相等的数的乘积,注意不要计算重复。

可以分治解决这个问题。我们每次找到区间内最小值(多个取最左边的),递归左区间,递归右区间。

 

对于每一个分治的区间L,R,我们用set去维护所有数向左取模和所有数向右取模。

那么计算的时候,先分别把左区间向右的mod apos, 右区间向左的mod pos,这里注意,取模的时候先二分找到第一个大于apos的值,再向后依次取模,这样保证每次操作都会使一个数变小。(这里的复杂度是nlognlogn的,因为一个最多有效取模log次,那么n个数最多取模nlog次,再算上set的复杂度)。

然后统计答案,合并左右区间。

为了保证分治的复杂度,就是要启发式分治嘛。

统计答案的时候要遍历小的区间,二分大的区间。合并的时候也是把小区间插入到大的区间里去。

这样复杂度也是nloglog的嘛。

 

#include <bits/stdc++.h>

using namespace std;

#define N 200025
#define M 610
#define ll long long
#define mod 1000000007
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define inf 0x3f3f3f3f
#define ld long double
#define pii pair<int,int>
#define pdd pair<double,double>
#define vi vector<int>
#define madd(a,b) (a+=(b)%mod)%=mod
#define lowb(c,len,x) lower_bound(c+1,c+len+1,x)-c
#define uppb(c,len,x) upper_bound(c+1,c+len+1,x)-c
#define ls i*2+1
#define rs i*2+2
//#define mid (l+r)/2
#define lson l,mid,ls
#define rson mid+1,r,rs
//#define root 1,cnt,0
#define ms(a,b) memset(a,b,sizeof a)
#define muti int T,cas=1;cin>>T;while(T--)
#define lll __int128
#define si short int
#define fi first
#define se second
#define l(x) (x&-x)
#define G(x) for( int ii=h[x];ii;ii=eg[ii].n )

int mm[2*N],n,las[N];
int dp[2*N][20],a[N],cnt;
set<pii>st[N];
set<pii>::iterator it,it1,itt;
ll ans=0;
void init()
{
    mm[0]=-1;
    go(i,1,n){
        dp[i][0]=i;
        mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
    }
    go(j,1,mm[n])
    for(int i=1; i+(1<<j)-1<=n; i++)
        dp[i][j]=a[dp[i][j-1]]<=a[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
}
int quy(int x,int y){
    if(x>y)return n+1;
    int k=mm[y-x+1];
    return a[dp[x][k]]<=a[dp[y-(1<<k)+1][k]]?dp[x][k]:dp[y-(1<<k)+1][k];
}
int join(int x,int y,int z){ //合并两个set,插入a[mid]
    if(st[x].size()>st[y].size())swap(x,y);
   //if(!st[x].size())return y;
    for(it=st[x].begin();it!=st[x].end();it++){
        it1=st[y].lower_bound(pii(it->fi,0));
        if(it1==st[y].end()||it1->fi!=it->fi)st[y].insert(*it);
        else {
            pii tmp=pii(it1->fi,it1->se+it->se);
            st[y].erase(it1);
            st[y].insert(tmp);
        }
    }
    st[x].clear();
    it=st[y].lower_bound(pii(z,0));
    if(it!=st[y].end()&&it->fi==z){
        pii tmp=pii(it->fi,it->se+1);
        st[y].erase(it);
        st[y].insert(tmp);
    }
    else st[y].insert(pii(z,1));
    return y;
}
void cal(int x,int y){ //统计答案
    if(st[x].size()>st[y].size())swap(x,y);
    if(!st[x].size())return ;
    for(it=st[x].begin();it!=st[x].end();it++){
        it1=st[y].lower_bound(pii(it->fi,0));
        if(it1!=st[y].end()&&it1->fi==it->fi)ans+=1ll*(it->se)*(it1->se);
    }
}
//void pri(int x){
//    cout<<":::::::::::::"<<endl;
//    for(it=st[x].begin();it!=st[x].end();it++){
//        cout<<it->fi<<'-'<<it->se<<' ';
//    }
//    cout<<endl<<endl;
//}
void upd(int x,int y){ //对set所有的值 mod a[mid]
    for(it=st[x].lower_bound(pii(y,0));it!=st[x].end();){
        pii tmp=pii(it->fi%y,it->se);
        it1=it;it++;
        st[x].erase(it1);
        itt=st[x].lower_bound(pii(tmp.fi,0));
        if(itt!=st[x].end()&&itt->fi==tmp.fi){
            pii tmp1=pii(itt->fi,itt->se+tmp.se);
            st[x].erase(itt);
            st[x].insert(tmp1);
        }
        else st[x].insert(tmp);
    }
}

pii solve(int l,int r,int fl=0){ 
    if(fl)ans++;
    if(l>=r){
        if(l>r)return pii(++cnt,++cnt);
        //cout<<fl<<endl;
        st[++cnt].insert(pii(a[l],1));
        st[++cnt].insert(pii(a[l],1));
        return pii(cnt-1,cnt);
    }
    int mid=quy(l,r);
    //递归左右区间
    pii pl=solve(l,mid-1),pr=solve(mid+1,r,a[quy(mid+1,r)]==a[mid]?1:0),res;
    //分别取模a[mid]
    upd(pr.fi,a[mid]);upd(pl.se,a[mid]);
    //特判区间内有多个相同的最小值
    it=st[pr.fi].lower_bound(pii(0,0));
    if(it!=st[pr.fi].end()&&it->fi==0)ans+=fl*(it->se);
    //统计答案
    cal(pl.se,pr.fi);
    //合并左右区间,a[mid]
    res=pii(join(pl.fi,pr.fi,a[mid]),join(pl.se,pr.se,a[quy(mid+1,r)]==a[mid]?0:a[mid]));

    return res;
}

int main()
{
    cin>>n;
    go(i,1,n)scanf("%d",&a[i]);
    a[n+1]=inf;
    init();
    solve(1,n);

    cout<<ans+n<<endl;
}
/*
10
10 9 8 7 1 2 3 4 5 6
*/

 

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

本课题设计了一种利用Matlab平台开发的植物叶片健康状态识别方案,重点融合了色彩与纹理双重特征以实现对叶片病害的自动化判别。该系统构建了直观的图形操作界面,便于用户提交叶片影像并快速获得分析结论。Matlab作为具备高效数值计算与数据处理能力的工具,在图像分析与模式分类领域应用广泛,本项目正是借助其功能解决农业病害监测的实际问题。 在色彩特征分析方面,叶片影像的颜色分布常与其生理状态密切相关。通常,健康的叶片呈现绿色,而出现黄化、褐变等异常色彩往往指示病害或虫害的发生。Matlab提供了一系列图像处理函数,例如可通过色彩空间转换与直方图统计来量化颜色属性。通过计算各颜色通道的统计参数(如均值、标准差及主成分等),能够提取具有判别力的色彩特征,从而为不同病害类别的区分提供依据。 纹理特征则用于描述叶片表面的微观结构与形态变化,如病斑、皱缩或裂纹等。Matlab中的灰度共生矩阵计算函数可用于提取对比度、均匀性、相关性等纹理指标。此外,局部二值模式与Gabor滤波等方法也能从多尺度刻画纹理细节,进一步增强病害识别的鲁棒性。 系统的人机交互界面基于Matlab的图形用户界面开发环境实现。用户可通过该界面上传待检图像,系统将自动执行图像预处理、特征抽取与分类判断。采用的分类模型包括支持向量机、决策树等机器学习方法,通过对已标注样本的训练,模型能够依据新图像的特征向量预测其所属的病害类别。 此类课题设计有助于深化对Matlab编程、图像处理技术与模式识别原理的理解。通过完整实现从特征提取到分类决策的流程,学生能够将理论知识与实际应用相结合,提升解决复杂工程问题的能力。总体而言,该叶片病害检测系统涵盖了图像分析、特征融合、分类算法及界面开发等多个技术环节,为学习与掌握基于Matlab的智能检测技术提供了综合性实践案例。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值