小奇的数列

https://www.zybuluo.com/ysner/note/1237581

题面

给定一个长度为\(n\)的数列,以及\(m\)次询问。每次询问在模\(p\)意义下,\([l,r]\)中的最小区间和。

  • \(40pts\ n\leq200,m\leq1000,p\leq500\)
  • \(100pts\ n\leq5*10^5,m\leq10^4,p\leq500\)

    解析

    或许是我看到的第\(n\)道卡不动暴力的题。(均因为不好造数据,类比[数字对][1])

    \(40pts\)算法

    枚举\(l,r\),用前缀和。
    复杂度\(O(mn^2)\)

    \(90pts\)算法

    注意如果询问的序列长度大于\(p\),那么答案一定为\(0\)
    因为在极端情况下,长度为\(p\)的区间中每个前缀和各不相同,覆盖了模\(p\)的所有余数。
    此时再加一个数,一定有前缀和相减得\(0\)
    特判即可。

\(100pts\)暴力算法

在上面特判的基础上,我们可以优化一下枚举过程。
我们从前往后枚举区间。对枚到位置的区间前缀和,再从大到小枚举数字,如果数字在前面出现过就\(break\),统计答案。
同时如果\(ans=0\)\(break\)
复杂度\(O(mp^2)\),但一点都不满,且难卡掉。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=5e5+100;
int n,m;
ll a[N],ans,res[N];
bool vis[505];
il ll gi()
{
   re ll x=0,t=1;
   re char ch=getchar();
   while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
   if(ch=='-') t=-1,ch=getchar();
   while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
   return x*t;
}
int main()
{
  freopen("seq.in","r",stdin);
  freopen("seq.out","w",stdout);
  n=gi();m=gi();
  fp(i,1,n) a[i]=gi();
  while(m--)
    {
      re int l=gi(),r=gi(),p=gi();ll ans=1e18;
      if(r-l+1>p) {puts("0");continue;}
      res[l-1]=0;
      fp(i,1,p) vis[i]=0;vis[0]=1;
      fp(i,l,r)
    {
      res[i]=(res[i-1]+a[i])%p;
      fq(j,res[i],0) if(vis[j]) {ans=min(ans,res[i]-j);break;}
      if(!ans) break;
      vis[res[i]]=1;
    }
      printf("%lld\n",ans);
    }
  fclose(stdin);
  fclose(stdout);
  return 0;
}

\(100pts\)正解算法

需用平衡树寻找最小差值。
我连平衡树都不怎么会,懒得写了
[1]: https://www.cnblogs.com/yanshannan/p/9060931.html

转载于:https://www.cnblogs.com/yanshannan/p/9414650.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值