【JZOJ 5428】【NOIP2017提高A组集训10.27】查询

本文介绍了一种针对特定问题的优化暴力算法实现,通过改进遍历方式并利用哈希表减少重复计算,将复杂度从简单的逐位跳转降低到跳至相同元素,有效提升效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给出一个长度为n的序列a[]
给出q组询问,每组询问形如

Solution

其实打一个不要太暴力的暴力即可,
暴力的暴力是一位一位的跳,把它改成跳到下一个相同的即可,
一样的询问用哈希判断啦,

复杂度:O(n2)

Code

//所以你们跑得都比我快的原因是你们不用MAP咯~

#include <cstdio>
#include <algorithm>
#include <map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
const int N=8500,INF=2147483640;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
map<int,int>Ans,bh;
int a[N],zx[N],nm[N];
int z[N*2][2],TI;
int main()
{
    freopen("query.in","r",stdin);
    freopen("query.out","w",stdout);
    int q,w;
    read(n),read(m);
    w=0;
    fo(i,1,n)
    {
        read(q);
        int t=bh[q];
        zx[i]=t;
        a[i]=(t?a[t]:(++w));
        bh[q]=i;
        nm[a[i]]++;
    }
    fo(I,1,m)
    {
        read(q),read(w);
        q=bh[q],w=bh[w];
        if(q==w){printf("%d\n",n*(n+1)/2);continue;}
        if(q>w)swap(q,w);
        if(nm[a[q]]>nm[a[w]])swap(q,w);
        int Q=q,W=w;
        if(Ans[q*(n+1)+w]){printf("%d\n",Ans[q*(n+1)+w]);continue;}
        TI++;
        int t=0,t1=0;
        z[n][1]=TI,z[n][0]=n+1-max(q,w);
        ans=z[n][0]*(z[n][0]-1)/2;
        for(;q||w;)
        {
            if(q>w)
            {
                int nx=q-max(zx[q],w);
                t++;
                int j=n+t-t1;
                if(z[j][1]<TI)z[j][1]=TI,z[j][0]=0;
                ans+=z[j][0]*nx+(nx-1)*nx/2;
                z[j][0]+=nx;
                q=zx[q];
            }else
            {
                int nx=w-max(zx[w],q);
                t1++;
                int j=n+t-t1;
                if(z[j][1]<TI)z[j][1]=TI,z[j][0]=0;
                ans+=z[j][0]*nx+(nx-1)*nx/2;
                z[j][0]+=nx;
                w=zx[w];
            }
        }
        Ans[Q*(n+1)+W]=ans;
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值