暂无链接
小 X 有一块
的巨大面包,上面有
个葡萄干,第
个葡萄干的位置在第
行
列,任意两个葡萄干都不在同一位置。
现在小 X 的朋友小 C 来了,小 X 要从这块面包上切下呈矩形的一块给小 C。但是如果切下来的面包上一个葡萄干都没有,小 X 会很没面子,于是小 X 的一个合法的切割方案要满足切下的部分是含有至少一个葡萄干的矩形。现在小 X 想知道:所有合法的切割方案切下的部分包含葡萄干的个数的方差是多少?为了方便,请输出答案对
取模的结果,保证数据是在一定范围内随机生成的。
第一行,三个正整数
和
。
接下来
行,每行两个整数
和
。
一行,包含一个非负整数,表示答案对
取模的结果。
注意,你的答案应该在
的范围内。
1 2 2
1 1
1 2
887328314
有三种合法方案,其中两种方案包含一个葡萄干,一种方案包含两个葡萄干,所以方差为 ,对 取模得到
见下发文件中的 。
见下发文件中的 。
对于所有的数据,
;
;
;
。
对于每个子任务的特殊限制:
Subtask1(20pts):
;
Subtask2(25pts):
;
Subtask3(15pts):
;
Subtask4(40pts): 无特殊限制。
按照我不知道的一个套路,我们先化简一波方差的式子,设
为第
个合法矩形中的点数,
为合法的矩形个数:
第二个东西非常好求,我们直接枚举每个点,看它对几个矩形有贡献,就求到了 ;第一个东西又要用到一个套路, 相当于一个矩形里的点对数(包括自己跟自己),我们只需要 枚举点对,看它们对几个矩形产生了贡献,就能统计出 。
那么问题来了, 怎么求?
我们可以先枚举右下角的行数,在那一行上从左到右加入在右下角上面的点,维护一个左上角坐标范围的单调栈,就能统计出有多少个矩形包含了至少一个点,大致如下图:
单调栈维护之后:
愉快地统计出 之后当然要愉快的 啦。
#include<bits/stdc++.h> #define ll long long using namespace std; const int M=2005,mod=998244353; struct sd{int x,y;}ptx[M],pty[M],sta[M]; int sum[M],tot,top,sum1,sum2,n,m,k; bool cmpy(sd a,sd b){return a.y==b.y?a.x>b.x:a.y<b.y;} bool cmpx(sd a,sd b){return a.x<b.x;} ll power(ll x,ll p){ll r=1;for(;p;p>>=1,x=x*x%mod)if(p&1)r=r*x%mod;return r;} void in(){scanf("%d%d%d",&n,&m,&k);for(int i=1;i<=k;++i)scanf("%d%d",&ptx[i].x,&ptx[i].y),pty[i]=ptx[i];} void ac() { for(int i=1;i<=k;++i)(sum1+=1ll*ptx[i].x*(n-ptx[i].x+1)%mod*ptx[i].y%mod*(m-ptx[i].y+1)%mod)%=mod; for(int i=1;i<=k;++i)for(int j=1;j<=k;++j) (sum2+=1ll*min(ptx[i].x,ptx[j].x)*(n-max(ptx[i].x,ptx[j].x)+1)%mod*min(ptx[i].y,ptx[j].y)%mod*(m-max(ptx[i].y,ptx[j].y)+1)%mod)%=mod; sort(ptx+1,ptx+1+k,cmpx);sort(pty+1,pty+1+k,cmpy);ptx[k+1].x=n+1; for(int i=k,j,tmp;i>=1;--i)if(ptx[i].x!=ptx[i+1].x) { for(top=0,tmp=0,j=1;j<=k;++j) { if(pty[j].x>ptx[i].x)continue; (tmp+=1ll*sum[top]*(pty[j].y-sta[top].y)%mod)%=mod; for(;pty[j].x>sta[top].x&⊤--top); sta[++top]=pty[j]; sum[top]=(sum[top-1]+1ll*pty[j].x*(pty[j].y-sta[top-1].y)%mod)%mod; } (tot+=1ll*(tmp+1ll*sum[top]*(m-sta[top].y+1)%mod)*(ptx[i+1].x-ptx[i].x)%mod)%=mod; } tot=power(tot,mod-2); printf("%lld",(1ll*sum2*tot%mod-1ll*sum1*tot%mod*sum1%mod*tot%mod+mod)%mod); } int main(){in(),ac();}