您的位置:首页 > 产品设计 > UI/UE

hdu5286 wyh2000 and sequence

2016-07-08 20:30 471 查看
  题目大意:给一段长度为N的序列,每次询问l-r(l和r和上一次询问的答案有关)内 不同的数的 出现次数的次方 的和。

大体思路就是,把n个数分成sqrt(n)块,每块sqrt(n)个数,然后求出任意两块i到j(包含第i块和第j块)的ans,对于每次询问l和r,找到刚好包含l和r的一段连续的块,因为我们已经知道了这段连续块的答案,所以只要再去掉两段多出来的一部分,就好了。

为了得到任意两块间的答案G[i][j],我们可以枚举每个块的起点,然后for到最后,暴力一边,就好了,

对于多出来的一部分,我们只要知道这一部分里的数,在包含它的连续块中已经出现了几次,然后就可以很容易地更新答案了。于是我们可以先预处理出一个后缀和cnt[i][j]:表示从第i块开始,第j小的数出现了多少次,然后,对于每次询问q,我们 只要 只要 只要 (后缀和减一下)找到这一部分里的数在连续的块中出现了次数就好了,别的数就算了,都找的话,肯定超时。

之前还要预处理各种数次方的结果,还要排序,去重。
#include <bits/stdc++.h>
using namespace std;
const int MOD=1000000007;
const int maxn=5e4+5;
int cnt[240][maxn];//cnt[i][j]:从第i块开始到最后第j小的数出现的次数
long long A[maxn],a[maxn],num[maxn],vis[maxn];
int pos[maxn];//pos[i]:在A中下标为i的数是第几小
long long G[240][240];//G[i][j]:块i~j的答案
vector<long long>v[maxn];//v[i][j]:第i小的数的j次方
int n,m,unit,len,l,r;
int solve(int l,int r)
{
int L=l/unit,R=r/unit;//获取所在的块
long long ans=G[L][R];
int LL=L*unit,RR=min(n-1,(R+1)*unit-1);//获取具体下标的的范围,且LL~RR肯定包含l~r的
for(int i=LL;i<l;i++) num[pos[i]]=cnt[L][pos[i]]-cnt[R+1][pos[i]];
for(int i=r+1;i<=RR;i++) num[pos[i]]=cnt[L][pos[i]]-cnt[R+1][pos[i]];
while(LL<l)
{
ans-=v[pos[LL]][num[pos[LL]]];
num[pos[LL]]--;
ans+=v[pos[LL]][num[pos[LL]]];
LL++;
}
while(RR>r)
{
ans-=v[pos[RR]][num[pos[RR]]];
num[pos[RR]]--;
ans+=v[pos[RR]][num[pos[RR]]];
RR--;
}
return (ans%MOD+MOD)%MOD;
}
int main()
{
int i,j,k,T;
scanf("%d",&T);
while(T--)
{
int la=0;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%lld",&A[i]);
a[i]=A[i];
}
sort(a,a+n);
len=unique(a,a+n)-a;
for(i=0;i<len;i++) v[i].clear(),v[i].push_back(0),vis[i]=0;
for(i=0;i<n;i++)
{
pos[i]=lower_bound(a,a+len,A[i])-a;//确定A[i]是第几小
vis[pos[i]]++;
}
for(i=0;i<len;i++)
{
long long p=1;
for(j=0;j<vis[i];j++)
{
p=p*a[i]%MOD;
v[i].push_back(p);
}
}
unit=sqrt(n);
memset(cnt,0,sizeof(cnt));
for(i=0;i*unit<n;i++)
{
long long ans=0;
memset(num,0,sizeof(num));
for(j=i*unit;j<n;j++)
{
cnt[i][pos[j]]++;
ans-=v[pos[j]][num[pos[j]]];
num[pos[j]]++;
ans+=v[pos[j]][num[pos[j]]];
if((j+1)%unit==0 || j==n-1)
G[i][j/unit]=(ans%MOD+MOD)%MOD;
}
}
while(m--)
{
int L,R;
scanf("%d%d",&L,&R);
l=min((L^la)%n,(R^la)%n);
r=max((L^la)%n,(R^la)%n);
la=solve(l,r);
printf("%d\n",la);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: