hdu_5286_wyh2000 and sequence(分块)


题目链接:hdu_5286_wyh2000 and sequence

题意:

给一段长度为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,我们 只要 只要 只要 (后缀和减一下)找到这一部分里的数在连续的块中出现了次数就好了,别的数就算了,都找的话,肯定超时。

之前还要预处理各种数次方的结果,还要排序,去重。

cnt[i][j]:从第i块开始到最后第j小的数出现的次数

pos[i]:在A中下标为i的数是第几小

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4 typedef long long ll;
 5 
 6 const int N=5e4+7,P=1e9+7;
 7 
 8 int sqr,n,m,l,r,len,t,pos[N],cnt[240][N];
 9 ll A[N],a[N],num[N],vis[N];
10 vector<ll>v[N];//第i小的数的j次方
11 ll G[240][240];//块i到j的答案
12 
13 int T_T(int l,int r)
14 {
15     int L=l/sqr,R=r/sqr;
16     ll ans=G[L][R];
17     int LL=L*sqr,RR=min(n-1,(R+1)*sqr-1);
18     F(i,LL,l-1)num[pos[i]]=cnt[L][pos[i]]-cnt[R+1][pos[i]];
19     F(i,r+1,RR)num[pos[i]]=cnt[L][pos[i]]-cnt[R+1][pos[i]];
20     while(LL<l)
21     {
22         ans-=v[pos[LL]][num[pos[LL]]];
23         ans+=v[pos[LL]][--num[pos[LL]]];
24         LL++;
25     }
26     while(RR>r)
27     {
28         ans-=v[pos[RR]][num[pos[RR]]];
29         ans+=v[pos[RR]][--num[pos[RR]]];
30         RR--;
31     }
32     return (ans%P+P)%P;
33 }
34 
35 int main()
36 {
37     scanf("%d",&t);
38     while(t--)
39     {
40         scanf("%d%d",&n,&m);
41         F(i,0,n-1)scanf("%lld",a+i),A[i]=a[i];
42         sort(a,a+n),len=unique(a,a+n)-a;
43         F(i,0,len-1)v[i].clear(),v[i].push_back(0),vis[i]=0;
44         F(i,0,n-1)vis[pos[i]=lower_bound(a,a+len,A[i])-a]++;
45         F(i,0,len-1)
46         {
47             ll p=1;
48             F(j,1,vis[i])v[i].push_back(p=p*a[i]%P);
49         }
50         sqr=sqrt(n+0.5);
51         memset(cnt,0,sizeof(cnt));
52         for(int i=0;i*sqr<n;i++)
53         {
54             ll ans=0;
55             memset(num,0,sizeof(num));
56             for(int j=i*sqr;j<n;j++)
57             {
58                 cnt[i][pos[j]]++;
59                 ans-=v[pos[j]][num[pos[j]]];
60                 ans+=v[pos[j]][++num[pos[j]]];
61                 if((j+1)%sqr==0||j==n-1)G[i][j/sqr]=(ans%P+P)%P;
62             }
63         }
64         int la=0;
65         while(m--)
66         {
67             int L,R;
68             scanf("%d%d",&L,&R);
69             l=(L^la)%n,r=(R^la)%n;
70             if(l>r)l^=r,r^=l,l^=r;
71             printf("%d\n",la=T_T(l,r));
72         }
73     }
74     return 0;
75 }
View Code

优质内容筛选与推荐>>
1、js字符串替换 - 无replaceAll替换所有字符串的解决方案
2、快速理解高性能HTTP服务端的负载均衡技术原理(转)
3、Struts2版本更新报错:>>> ActionContextCleanUp <<< is deprecated! Please use the new filters!
4、[USACO12JAN]Video Game Combos
5、Linux入门——samba


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn