[貪心][前綴和] JZOJ P1795 教主的別墅
阿新 • • 發佈:2018-02-07
col sca get 最小 span 字符 con gpo abs
題解
- 我們把0當成-1做,跑一邊前綴和
- 用zero記錄下有多少個位置為0
- 如果zero比分組的組數多而且前綴和最後不為0,將x定為0(後面會解釋x是什麽)
- 否則,將x定為abs(abs(sum[n-1])-1)/m+1(也就是將sum平均分到每一組的差值,向上取整)
- 然後我們就可以模擬了,如果當前分了cnt>=m-1,將後面所有的數塞到第m組
- 如果abs(sum[n-1]-sum[i])/(m-cnt-1)<=x,也就是將i處斷後,後面的平均差值小於x,那當然是可以斷的
- 那麽怎麽滿足字典序最小的條件呢?
- 當然是有的取盡量先取
- 就字典序最大時,將數組反過來再跑一遍,從大到小輸出
代碼
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 int n,m,sum[5000010],ans,fen[5000010]; 7 char s[5000010]; 8 int abs(int x){return x>0?x:-x;} 9 void greedy() 10 { 11 int cnt=0,num=-1,zero=0,k=0; 12 memset(sum,0,sizeof(sum)); 13 for (int i=0;i<=n-1;i++) 14 { 15 if (s[i]==‘1‘) k++; else k--; 16 sum[i]=k; 17 if (!k) zero++; 18 } 19 if (!sum[n-1]&&zero>=m) ans=0; else ans=abs(abs(sum[n-1])-1)/m+1; 20 for (int i=0;i<=n-1;i++) 21 { 22 if (cnt>=m-1) 23 { 24 fen[cnt++]=n-i; 25 break; 26 } 27 if (abs(sum[n-1]-sum[i])<=ans*(m-cnt-1)) 28 { 29 fen[cnt++]=i-num; 30 num=i; 31 } 32 } 33 } 34 int main() 35 { 36 scanf("%d%d\n",&n,&m); 37 gets(s); 38 greedy(); 39 for (int i=0;i<m;i++) printf("%d ",fen[i]); printf("\n"); 40 reverse(&s[0],&s[n]); 41 greedy(); 42 for (int i=0;i<m;i++) printf("%d ",fen[m-i-1]); 43 return 0; 44 }
[貪心][前綴和] JZOJ P1795 教主的別墅