【2018.6.29NOIP模拟】T1区间interval
【问题描述】
给出一个长度为 n 的序列 a[1]…a[n]。
给出 q 组询问,每组询问形如
【输入格式】
第一行两个数 n 和 q。
第二行 n 个数 a[i]。
接下来 q 行,每行两个数 x,y 表示一组询问。
【输出格式】
输出 q 行,每行一个数表示对应询问的答案。
【样例输入】
3 2
1 2 1
1 2
4 5
【样例输出】
2
6
【数据规模与约定】
对于 30%的数据:1≤n≤100;1≤q≤1000。
对于另外 30%的数据:序列中只有最多 50 种不同数字且 1≤n≤1000。
对于 100%的数据:1≤n≤8000;1≤q≤500000;1≤x,y,a[i]≤10^9。
反正考试的时候写了两个subtask总计60分然后爆零
我也不知道发生了什么
然后说说正解:
对于两个数x和y,只有出现x和y的位置对答案有影响,所以我们把每个数出现的位置存下来,然后对于x和y,我们考虑怎么求解:
首先我们如果定义一个数res,当出现x时res++,出现y时res–,我么可以发现如果两个端点的res值相等,那么这是一个可行区间
然后我们就在所有出现过x和y的节点处更新res就好了,我们用cnt数组统计在last前出现的相同的res次数,然后当前这段区间的长度和cnt[res+n]来更新答案,最后更新一下cnt数组和last值和当前的res就好了
我也不知道为什么,cout比printf更慢。。。
扫描二维码关注公众号,回复:
1859808 查看本文章
#include<bits/stdc++.h>
using namespace std;
int read(){
int ans=0,w=1;char c=getchar();
while(!isdigit(c)&&c!='-')c=getchar();
if(c=='-')c=getchar(),w=-1;
while(isdigit(c))ans=ans*10+c-'0',c=getchar();
return ans*w;
}
#define N 8010
int n,q,tot=0,a[N],b[N],cnt[N<<2];
int ans[110][110];
vector<int> G[N],p;
map<int,int> mp;
int main(){
int n=read(),q=read();
for(int i=1;i<=n;i++)b[i]=a[i]=read();
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
if(b[i]!=b[tot])b[++tot]=b[i],mp[b[i]]=tot;
for(int i=1;i<=n;i++)G[mp[a[i]]].push_back(i);
for(int i=0;i<=tot;i++)G[i].push_back(n+1);
while(q--){
int x=mp[read()],y=mp[read()];
int tx=0,ty=0,res=0,last=0,sum=0;
cnt[n]++;
while(last<n){
int tmp=sum+n,len;
if(G[x][tx]<G[y][ty])len=G[x][tx++]-last-1,sum++;
else len=G[y][ty++]-last-1,sum--;
res+=len*cnt[tmp]+len*(len-1)/2;
cnt[tmp]+=len;
last+=len;
p.push_back(tmp);
}
while(!p.empty())cnt[p.back()]=0,p.pop_back();
cout<<res<<"\n";
}
return 0;
}