k 倍子矩形(列舉暴力)
阿新 • • 發佈:2021-11-11
差分/字首和思路的深度應用,其實似乎是優化列舉量的常見方法但是我卻不知道……
相等,則這一段矩形面積一定能被 \(k\) 整除。我們不妨開一組桶,記錄每個相同的 \(c\) 值出現了多少次,最後掃一遍 \(1\to k\),統計答案。
。
題目放在洛谷U188718,出處在 SDFZ-NOIP2021 模擬 11-T2。
顯然的暴力是 \(\mathcal{O(n^4)}\),預處理二維字首和,列舉左上角、右下角,期望得分 \(60\),具體因實現而異。
觀察資料範圍發現 \(n\le 400\),只需要優化到 \(\mathcal{O(n^3)}\) 即可。考慮 \(n^2\) 地列舉一個縱向區間 \([l,r]\),如下圖所示:
對於這個區間,用指標從左向右掃,記錄字首矩形面積 \(c\)。在已經預處理了縱向字首和的基礎上,這是 \(\mathcal{O(m)}\) 的。在模 \(k\) 意義下,如果某時刻的 \(c\) 和之前一時刻的 \(c'\)
還是以上圖為例,紅色的線是指標,從左往右掃。在 \(i\) 的位置,\(c=S_{綠色矩形}\) 且 \(c\equiv m(\mod k)\);走到 \(j\) 的位置,\(c=S_{藍色矩形}\),恰巧又有 \(c\equiv m(\mod k)\)。因此 \(k\vert S_{紅色矩形}\),答案++……掃完之後,\(\mod k\) 結果為 \(m\) 的結果記為 \(cnt_m\),其對答案的總貢獻為 \(cnt_m\times (cnt_m-1)/2\)
特別地,我們應當初始化 \(cnt_0\gets 1\),否則如果一個矩形本身面積為 \(k\) 的倍數,那它自己的 \(1\) 發貢獻將被漏算,導致 WA 穿地心。
下面是 AC 程式碼:
int main(){ int n,m,k; read(n),read(m),read(k); rep(i,1,n) rep(j,1,m){ int x; read(x); s[i][j]=(s[i-1][j]+x)%k;//對豎列求字首和 } long long ans=0; rep(i,1,n) rep(j,i,n){ //列舉區間(縱向) int c=0,t=1; cnt[0]=1,v[1]=0; rep(p,1,m){//指標掃描(橫向) if((c+=s[j][p]-s[i-1][p])<0) c+=k; if(c>=k) c-=k;//相當於取模 !cnt[c]?cnt[v[++t]=c]=1:++cnt[c];//扔進桶裡 } rep(p,1,t){ int& x=cnt[v[p]];//沒別的意思,壓行罷了 ans+=x*(x-1)/2,x=0; } } write(ans),EN; }