【题解】[HNOI2012] 双十字

这题呢,暴露出来一个问题,就是 我对暴力数据结构的掌控力还是不强

导致最后手忙脚乱还是没调出来。(当然思维上也有一些问题,有点想复杂了)

第一种做法,树状数组。

∑ i = 1 n ∑ j = i n ∑ k = j n d i = ∑ i = 1 n d i ( n − i + 1 ) ( n − i + 2 ) 2 = 1 2 ∑ i = 1 n ( ( n 2 + 3 n + 2 ) × d i − ( 2 n + 3 ) × i × d i + i 2 × d i ) \sum_{i=1}^n\sum_{j=i}^n\sum_{k=j}^nd_i \\ =\sum_{i=1}^nd_i\frac{(n-i+1)(n-i+2)}{2} \\ =\frac{1}{2}\sum_{i=1}^n((n^2+3n+2)\times d_i-(2n+3)\times i\times d_i+i^2\times d_i) i=1nj=ink=jndi=i=1ndi2(ni+1)(ni+2)=21i=1n((n2+3n+2)×di(2n+3)×i×di+i2×di)

分别维护 d i , i × d i , i 2 × d i d_i,i\times d_i,i^2\times d_i di,i×di,i2×di 的前缀和即可。

第二种做法,线段树。

第一种维护方式,分别维护两个线段树,表示 a i , i × a i a_i,i\times a_i ai,i×ai 的区间和。

第二种维护方式,用等差数列来维护。(考场上这个做法写 wa 了,调了半天)

这里可能要分讨一下。

我不太推荐线段树的写法,因为空间消耗比较大,

失之毫厘,差之千里

#include<bits/stdc++.h> #define inf 0x3f3f3f3f #define ll long long using namespace std; const int N=4e6+5; const int mod=1e9+9; //树状数组 ??? //区间修改 + 区间的前缀和的前缀和 int R,C,n,vis[N],le[N],ri[N],len[N]; ll bit1[N],bit2[N],bit3[N],inv2=500000005,res; vector<pair<int,int>> op; void Mod(ll &x,ll y) { x=(x+y)%mod; } int has(int x,int y) { return (x-1)*C+y; } void add(int x,ll y) { for(int i=x;i<=C;i+=i&-i) { Mod(bit1[i],y); Mod(bit2[i],x*y%mod); Mod(bit3[i],x*y%mod*x%mod); } } ll qry(int x) { ll tmp1(0),tmp2(0),tmp3(0); for(int i=x;i;i-=i&-i) { Mod(tmp1,bit1[i]); Mod(tmp2,bit2[i]); Mod(tmp3,bit3[i]); } return inv2*((1ll*x*x+3*x+2)%mod*tmp1%mod-(2*x+3)*tmp2%mod+tmp3)%mod; } ll solve(int c,int l,int r) { if(l>r) return 0; ll tot=0; for(int i=l;i<=r;i++) { len[i]=min(le[has(i,c)],ri[has(i,c)]); if(len[i]>0) { Mod(tot,qry(len[i]-1)*(r-i)%mod); } // printf("%lld\n",tot); if(i-1>=l&&len[i-1]>0) { add(1,i-1-l); add(len[i-1]+1,-(i-1-l)); op.push_back(make_pair(len[i-1],i-1-l)); } } for(auto t:op) { add(1,-t.second); add(t.first+1,t.second); } op.clear(); return tot; } int main() { scanf("%d%d",&R,&C); for(int i=1;i<=R*C;i++) vis[i]=1; scanf("%d",&n); for(int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); vis[has(x,y)]=0; } for(int i=1;i<=R;i++) { for(int j=1;j<=C;j++) { if(vis[has(i,j)]) { le[has(i,j)]=(j>1&&vis[has(i,j-1)])?le[has(i,j-1)]+1:0; } } for(int j=C;j>=1;j--) { if(vis[has(i,j)]) { ri[has(i,j)]=(j<C&&vis[has(i,j+1)])?ri[has(i,j+1)]+1:0; } } } for(int j=1;j<=C;j++) { int l=inf,r=0; for(int i=1;i<=R+1;i++) { if(vis[has(i,j)]) { l=min(l,i),r=max(r,i); } else { Mod(res,solve(j,l,r)); l=inf,r=0; } } } printf("%lld",(res+mod)%mod); }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530167.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示