JZOJ 5410. 【NOIP2017提高A组集训10.22】小型耀斑
Description
Uthuso 的核反應失控了,她在地靈殿釋放了幾顆大核彈.地靈殿可以看做一個大小為n*m 的矩陣.一顆大小為k 的核彈,對于任意一個與爆炸中心曼哈頓距離小于k 的地區,會造成(k-(該地區到爆炸中心曼哈頓距離))*(該地區的價值)的損失.現在,地靈殿方面想統計一下每顆核彈造成的損失,請你來幫忙計算.
Input
從flare.in 中讀入數據第一行為兩個整數n,m接下來n 行每行m 個整數,代表第i 行第j 個區域的價值接下來一行為一個整數Q,代表核彈的數目.接下來Q 行每行三個整數x,y,k,代表第i 顆核彈的爆炸中心以及它的大小.
Output
輸出到文件flare.out 中Q 行,每行1 個整數,代表第i 顆核彈的損失.
Sample Input
5 51 2 3 4 59 8 7 6 52 3 3 3 36 6 6 6 61 4 2 8 55
1 1 15 5 13 3 32 2 24 2 2
Sample Output
1
5
833731
Data Constraint
對于30%的數據,滿足n<=300,m<=300,Q<=300對于60%的數據,滿足n<=300,m<=300對于100%的數據,滿足1<=n<=2000,1<=m<=2000,1<=Q<=200000,1<=k<=min(x,y,n-x+1,m-y+1),1<=每個區域的價值<=1000000
Hint
由于本題輸入輸出量極大,請使用較快的輸入輸出方式
Solution
這題我的方法比較笨,代碼打了100年……
這題是預處理和前綴和的終極體現,想出如何通過前綴和來計算答案十分關鍵。
對于每個核彈,要計算的答案是一個菱形,而且菱形上的點還要乘上系數,怎么辦呢?
考慮將每個菱形分割成四個三角形,對于每個三角形分別統計即可。
對于右上角的三角形(其他同理,這里不做討論),如上圖所示:
設 s[i][j] 表示到第 i 行、第 j 列 的一個鋸齒狀的價值和(系數全為1),顯然有:
s[i][j]=s[i?1][j?1]+∑k=1ja[i][k]顯然我們可以先做一遍前綴和預處理出 a 矩陣的子矩陣和。
再設 h[i][j] 表示有系數的鋸齒陣的價值和(系數就是曼哈頓距離),則有:
h[i][j]=h[i][j?1]+s[i][j]將前一個鋸齒陣再覆蓋上系數為1的鋸齒陣,就能疊起前面的系數。
根據上圖,用 h[x][y+k?1]?h[x?k][y?1] 就還剩一個樓梯形,還需要減去一個矩陣。
于是設 g[i][j] 表示從左下角到 (i,j) 的矩陣和(帶系數,還是曼哈頓距離),則有:
g[i][j]=g[i+1][j]+左下角到?(i,j)?的矩陣和(系數為1)那個要減的矩陣就等于:
g[x?k+1][y?1]?g[x+1][y?1]?k(乘上系數)+從左上角到?(x,y?1)?的矩陣和這樣我們就能統計出一個三角形的價值和了,其他三角形同理。
總時間復雜度為大常數的 O(N?M) 。
Code
#include<cstdio> using namespace std; const int N=2002; long long f[N][N],g[N][N],s[N][N],k[N][N]; long long g1[N][N],s1[N][N],k1[N][N]; long long g2[N][N],s2[N][N],k2[N][N]; long long g3[N][N],s3[N][N],k3[N][N]; inline int read() { int X=0,w=1; char ch=0; while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar(); return X*w; } int main() { int n=read(),m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+read(); s[i][j]=s[i-1][j-1]+f[i][j]-f[i-1][j]; k[i][j]=k[i][j-1]+s[i][j]; } for(int j=m;j;j--) for(int i=1;i<=n;i++) { s2[i][j]=s2[i-1][j+1]+f[i][j]-f[i][j-1]; k2[i][j]=k2[i-1][j]+s2[i][j]; } for(int j=1;j<=m;j++) for(int i=1;i<=n;i++) { s3[i][j]=s3[i-1][j-1]+f[i][j]-f[i][j-1]; k3[i][j]=k3[i-1][j]+s3[i][j]; } for(int i=1;i<=n;i++) { long long sum=0; for(int j=m;j;j--) { sum+=f[i][m]-f[i-1][m]-f[i][j-1]+f[i-1][j-1]; g3[i][j]=g3[i-1][j]+f[i-1][m]-f[i-1][j-1]+sum; } } for(int i=1;i<=n;i++) { long long sum=0; for(int j=1;j<=m;j++) { sum+=f[i][j]-f[i-1][j]; g2[i][j]=g2[i-1][j]+f[i-1][j]+sum; } } for(int i=1;i<=n;i++) for(int j=m;j;j--) { s1[i][j]=s1[i-1][j+1]+f[i][m]-f[i-1][m]-f[i][j-1]+f[i-1][j-1]; k1[i][j]=k1[i][j+1]+s1[i][j]; } for(int i=n;i;i--) { long long sum=0; for(int j=1;j<=m;j++) { sum+=f[i][j]-f[i-1][j]; g[i][j]=g[i+1][j]+f[n][j]-f[i][j]+sum; } } for(int i=n;i;i--) { long long sum=0; for(int j=m;j;j--) { sum+=f[i][m]-f[i-1][m]-f[i][j-1]+f[i-1][j-1]; g1[i][j]=g1[i+1][j]+f[n][m]-f[n][j-1]-f[i][m]+f[i][j-1]+sum; } } int q=read(); while(q--) { int x=read(),y=read(),K=read(); long long ans=k[x][y+K-1]-k[x-K][y-1]; long long sum=g[x-K+1][y-1]-g[x+1][y-1]-(f[n][y-1]-f[x][y-1])*K; sum+=f[x][y-1]-f[x-K][y-1]; ans-=sum; ans+=k1[x][y-K+1]-k1[x-K+1][y]; sum=g1[x-K+2][y]-g1[x+1][y]-(f[n][m]-f[x][m]-f[n][y-1]+f[x][y-1])*(K-1); sum+=f[x][m]-f[x-K+1][m]-f[x][y-1]+f[x-K+1][y-1]; ans-=sum; ans+=k2[x+K-1][y]-k2[x][y+K-1]; sum=g2[x][y+K-2]-g2[x][y-1]-f[x][y-1]*(K-1); sum+=f[x][y+K-2]-f[x][y-1]; ans-=sum; ans+=k3[x+K-2][y-1]-k3[x][y-K+1]; sum=g3[x][y-K+2]-g3[x][y]-(f[x][m]-f[x][y-1])*(K-2); sum+=f[x][y-1]-f[x][y-K+1]; ans-=sum; printf("%lld\n",ans); } return 0; }總結
以上是生活随笔為你收集整理的JZOJ 5410. 【NOIP2017提高A组集训10.22】小型耀斑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5405. 【NOIP2017
- 下一篇: JZOJ 5414. 【NOIP2017