由於「maximum level」和探照燈的覆蓋沒有單調性,因此能得到答案的方式大概就只有枚舉這個「maximum level」了
可是maximum level可能的數值多達10000個,而燈泡數又可以到1000000個,時間可不夠每次重算哪......怎麼辦呢?
為了方便說明,簡寫maximum level為$ML$
可以想像,在$ML$慢慢增加的時候,燈泡會一個一個「關掉」(因為不夠亮),而剩下的燈泡都會覆蓋四方$ML$長度的十字架區,而行與行、列與列之間又都是互相獨立的,因此可以分開來個別維護「直線上相鄰兩燈泡的最長距離」,看看任兩相鄰燈泡能不能都照亮它們之間的格子
當然,頭尾兩端是特殊情形,要分開考慮
可以用set維護直線上那些位置有燈泡,再用multiset維護這些燈泡將直線分成那些長度的區間。要考慮兩端的特殊情形,就把兩端的區間長度設為$inf$以免影響答案,再取出最左和最右的燈泡位置進行計算即可
當$ML$從小到大慢慢枚舉時,刪除燈泡的操作相信也不難想到要怎麼利用set和multiset的特性來維護,唯獨實作上容易出BUG而已XD
時間複雜度:$O(MN(\log N+\log M+\log (MN)))$
這裡提供一些測資讓你debug用:
3 3
2 0 2
0 2 0
2 0 2
3 3
2 0 2
0 1 0
2 0 2
3 3
1 1 1
1 0 1
1 1 1
3 3
2 2 2
2 0 2
2 2 2
4 4
2 2 2 2
2 0 0 2
2 0 0 2
2 2 2 2
5 5
2 2 2 2 2
2 0 0 0 2
2 0 0 0 2
2 0 0 0 2
2 2 2 2 2
code:
#include<cstdio> #include<set> #include<map> #include<cassert> #include<algorithm> using namespace std; const int INF=2147483647; multiset<int>MN; struct GapManager { set<int>LOC; multiset<int>GAP; int N; void clear(const int _n) { N=_n;LOC.clear(),GAP.clear(); LOC.insert(-INF/2),LOC.insert(INF/2); GAP.insert(INF/2+INF/2); } void insert(const int loc) { auto it=LOC.lower_bound(loc); const int r=(*it),l=(*--it); GAP.erase(GAP.find(r-l)); LOC.insert(loc); GAP.insert(r-loc),GAP.insert(loc-l); assert(GAP.size()+1==LOC.size()); } void erase(const int loc) { MN.erase(MN.find(GetValue())); auto it=LOC.find(loc); const int r=(*++it),l=(*----it); GAP.erase(GAP.find(r-loc)),GAP.erase(GAP.find(loc-l)); LOC.erase(loc); GAP.insert(r-l); MN.insert(GetValue()); assert(GAP.size()+1==LOC.size()); } int GetValue()const { if((int)GAP.size()==1)return INF-2; int lmx,rmx; if(true) { auto it=LOC.begin(); lmx=((*++it)+1)*2-1; it=LOC.end();it--; rmx=(N-(*--it))*2-1; } auto it=GAP.end();it--,it--; return max(max(lmx,rmx),it==GAP.begin()?0:(*--it)); } }HG[100],VG[10000]; int N,M,GRID[100][10000]; multimap<int,int>LEVEL; int Solve() { for(int level=1;!LEVEL.empty();level++) { while(!LEVEL.empty()&&(LEVEL.begin()->first)<level) { const int u=LEVEL.begin()->second; LEVEL.erase(LEVEL.begin()); HG[u/M].erase(u%M); VG[u%M].erase(u/M); } assert((int)MN.size()==N+M); // puts("pass"); // for(int i=0;i<N;i++) // { // printf("H[%d]:",i); // for(auto it:HG[i].LOC)printf(" %d",it);puts(""); // printf("G[%d]:",i); // for(auto it:HG[i].GAP)printf(" %d",it);puts(""); // } // for(int i=0;i<M;i++) // { // printf("V[%d]:",i); // for(auto it:VG[i].LOC)printf(" %d",it);puts(""); // printf("G[%d]:",i); // for(auto it:VG[i].GAP)printf(" %d",it);puts(""); // } // printf("MN:");for(auto it:MN)printf(" %d",it);puts(""); auto it=MN.end();it--; // printf("mx=%d\n",*it); if(((*it)+2)/2<=level)return level; } return -1; } int main() { // freopen("in.txt","r",stdin); while(scanf("%d%d",&N,&M)==2) { if(N==0&&M==0)break; for(int i=0;i<N;i++)HG[i].clear(M); for(int i=0;i<M;i++)VG[i].clear(N); LEVEL.clear(); for(int i=0;i<N;i++)for(int j=0;j<M;j++) { int &v=GRID[i][j];scanf("%d",&v); if(v)LEVEL.insert(make_pair(v,i*M+j)),HG[i].insert(j),VG[j].insert(i); } MN.clear(); for(int i=0;i<N;i++)MN.insert(HG[i].GetValue()); for(int i=0;i<M;i++)MN.insert(VG[i].GetValue()); const int ans=Solve(); if(ans!=-1)printf("%d\n",ans); else puts("NO ANSWER!"); } return 0; }
沒有留言:
張貼留言
歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原
注意:只有此網誌的成員可以留言。