退役快一年了以後又打了場緊張刺激的$CF$(斜眼笑)
而後發現$D$題和題解裏的大衆作法不太同樣 (思路清奇)
題意再也不贅述,咱們能夠看到這個題~~好作~~在只有一次擦除機會,嘗試以此爲突破口解決問題
咱們考慮擦除某一行(列同理),分別記錄這一行最左端和最右端的黑塊位置(分別記爲$l,r$)
這裏存在如下三種狀況:
1,這一行沒有黑塊,這時不管在哪擦除,這一行必然全白,記錄答案後再也不考慮
2,這一行的最左黑塊和最右黑塊之間的距離$>k$(即$r-l+1>k$),這時不管在哪擦除,這一行必然不會全白,再也不考慮
3,這一行最左黑塊和最右黑塊之間的距離$<=k$,考慮可以使得這一行全爲白色的擦除位置(假設咱們當前考慮的是第$i$行)
容易得出,對於擦除位置的選擇
可行的行:第$i-k+1((i-k+1)+k-1=i)$行到第$i$行
可行的列:第$l-k+1((l-k+1)+k-1=l)$列到第$l$列
即若是擦除位置$(x,y)$知足$i-k+1<=x<=i$且$l-k+1<=y<=l$,這一次擦除能夠使第$i$行變白
對於答案統計,天然想到二維前綴和
咱們只需在位置$(i-k+1,l-k+1),(i+1,l+1)+1$,$(i-k+1,l+1),(i+1,l-k+1)-1$便可(二維差分的常規操做)
差分完了再作前綴和便可得出答案(別忘了累加狀況一的答案)
$P.S.i-k+1$和$l-k+1$不要數組越界
上代碼:
ios
#include<iostream> #include<cstdio> using namespace std; const int maxn=2010; int n,k,ans[maxn][maxn],l[2][maxn],r[2][maxn],res,bs; bool exi[maxn][maxn]; int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { string s; cin>>s; for(int j=0;j<n;j++) if(s[j]=='W') exi[i][j+1]=0; else exi[i][j+1]=1; } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) if(exi[i][j]) { l[0][i]=j; break; } for(int j=n;j;j--) if(exi[i][j]) { r[0][i]=j; break; } if(!l[0][i]) bs++; } for(int j=1;j<=n;j++) { for(int i=1;i<=n;i++) if(exi[i][j]) { l[1][j]=i; break; } for(int i=n;i;i--) if(exi[i][j]) { r[1][j]=i; break; } if(!l[1][j]) bs++; } for(int i=1;i<=n;i++) { if(l[0][i]&&r[0][i]-l[0][i]+1<=k) { int minx=max(i-k+1,1),miny=max(1,r[0][i]-k+1); ans[minx][miny]++; ans[i+1][miny]--; ans[minx][l[0][i]+1]--; ans[i+1][l[0][i]+1]++; } if(l[1][i]&&r[1][i]-l[1][i]+1<=k) { int miny=max(i-k+1,1),minx=max(1,r[1][i]-k+1); ans[minx][miny]++; ans[minx][i+1]--; ans[l[1][i]+1][miny]--; ans[l[1][i]+1][i+1]++; } } for(int i=1;i<=n-k+1;i++) for(int j=1;j<=n-k+1;j++) { ans[i][j]+=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1]; res=max(res,ans[i][j]); } printf("%d\n",res+bs); return 0; }