標籤:des style blog http color java os io
4923 Room and Moor
Room and MoorTime Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 182 Accepted Submission(s): 50
Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0 or 1. In order to beat him, programmer Moor has to construct another sequence B = {B1, B2,... , BN} of the same length, which satisfies that:
Input The input consists of multiple test cases. The number of test cases T(T<=100) occurs in the first line of input.
For each test case:
The first line contains a single integer N (1<=N<=100000), which denotes the length of A and B.
The second line consists of N integers, where the ith denotes Ai.
Output Output the minimal f (A, B) when B is optimal and round it to 6 decimals.
Sample Input491 1 1 1 1 0 0 1 191 1 0 0 1 1 1 1 140 0 1 140 1 1 1
Sample Output1.4285711.0000000.0000000.000000
Source 2014 Multi-University Training Contest 6
Recommendhujie |
題意:輸入由1和0組成的A序列,求一個長度與A序列相同的、在實數[0,1]之間的不下降序列B,使得sum of (Ai-Bi)^2最小,輸出這個最小的sum。
題解:
先觀察一下,發現最左邊的0和最右邊的1可以忽視,因為我們可以把B左邊這段當做0,B右邊那段當1。解下來看剩下的。
假如有一段是1111.....00000,由x個1和y個0組成,則這一段最優的B是x/(x+y),也就是平均值,這可以通過範例看出。
而如果有兩段這樣的段,111...000 111....000,我們計算兩段分別的平均值,若左段小於等於右段,則左段用左段的平均值,右段用右段的平均值是最優的;若左段大於右段,則不能各用各的平均值了,我們把這兩段合作一段,用一起的平均值。
根據這個思想,我們把下降的段都合并了,得到平均值上升的若干段,各用各的平均值,哇,最優解!
合并時,從頭到尾,相鄰的組平均值比較。有可能會出現合并完這兩個,新組平均值比再前一個組的平均值還小的情況,所以我們每次合并,都要和之前的比較一發,保證隊列不下降。
代碼:
1 //#pragma comment(linker, "/STACK:102400000,102400000") 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<set> 10 #include<stack> 11 #include<queue> 12 using namespace std; 13 #define ll __int64 14 #define usint unsigned int 15 #define mz(array) memset(array, 0, sizeof(array)) 16 #define minf(array) memset(array, 0x3f, sizeof(array)) 17 #define REP(i,n) for(int i=0;i<(n);i++) 18 #define FOR(i,x,n) for(int i=(x);i<=(n);i++) 19 #define RD(x) scanf("%d",&x) 20 #define RD2(x,y) scanf("%d%d",&x,&y) 21 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) 22 #define WN(x) printf("%d\n",x); 23 #define RE freopen("D.in","r",stdin) 24 #define WE freopen("1.out","w",stdout) 25 26 const int maxn=100011; 27 28 struct pig {///分組,每個pig記錄一組的和與長度 29 int sum,len; 30 pig(int s,int l) { 31 sum=s; 32 len=l; 33 } 34 pig() {} 35 long double ave() {///還能算平均值,怕不怕 36 return sum*1.0/len; 37 } 38 }; 39 40 pig v[maxn]; 41 int vl,vr; 42 int n; 43 bool a[maxn]; 44 45 int main() { 46 int i,T,j; 47 int l,r; 48 int sum,len; 49 long double ans; 50 int flag; 51 scanf("%d",&T); 52 while(T--) { 53 scanf("%d",&n); 54 for(i=0; i<n; i++) 55 scanf("%d",&a[i]); 56 l=0; 57 r=n; 58 while(a[l]==0&&l<n)l++;///去除左邊的0 59 while(a[r-1]==1&&r>=0)r--;///去除右邊的1 60 sum=0.0; 61 flag=0; 62 len=0; 63 vl=0; 64 vr=0; 65 for(i=l; i<r; i++) {///將剩下的分成若干組不上升序列,記錄各組的和與長度 66 //cout<<i<<‘.‘<<sum<<‘/‘<<len<<endl; 67 if(a[i]==1) { 68 if(flag==0) 69 sum++,len++; 70 else if(flag==1) { 71 v[vr++]=(pig(sum,len)); 72 sum=a[i]; 73 len=1; 74 flag=0; 75 } 76 } else if(a[i]==0) { 77 len++; 78 if(flag==0) 79 flag=1; 80 } 81 } 82 if(len>0) v[vr++]=pig(sum,len);///把最後剩下的一組也加入 83 for(i=vl+1; i<vr; i++) { 84 if(v[i-1].ave()>v[i].ave()) {///若相鄰兩組平均值呈下降,則合并為一組 85 v[i].sum+=v[i-1].sum; 86 v[i].len+=v[i-1].len; 87 v[i-1].sum=0; 88 v[i-1].len=0; 89 for(j=i-1; j>=0; j--) 90 if(v[j].len>0) { 91 if(v[j].ave()>v[i].ave()) {///有可能合并完後小於更之前的平均值,若發生這種事,則把之前的也合并進來 92 v[i].sum+=v[j].sum; 93 v[i].len+=v[j].len; 94 v[j].sum=0; 95 v[j].len=0; 96 } 97 else break; 98 } 99 }100 }101 while(v[vl].len==0 && vl<vr) vl++;///去除開頭的空組102 // printf("vl=%d,vr=%d:",vl,vr);103 // for(i=vl;i<vr;i++)104 // printf("%.6f,%d ",v[i].sum,v[i].len);105 // puts("");106 ans=0.0;107 for(i=vl; i<vr; i++) {108 if(v[i].len!=0) {///若為非空組,則統計len*(1-ave)^2+(len-sum)*ave^2109 //cout<<v[i].sum<<‘,‘<<v[i].len<<‘,‘<<(double)v[i].ave()<<endl;110 //cout<<(long double)ave<<‘,‘<<(long double)ave2<<‘,‘<<(long double)(len-v[i].sum)<<endl;111 if(v[i].len>0) ans+=( v[i].ave() * v[i].ave() ) * (v[i].len-v[i].sum) + (1.0-v[i].ave())*(1.0-v[i].ave()) * v[i].sum;112 //cout<<ans<<endl;113 }114 }115 printf("%.6f\n",(double)ans);116 }117 return 0;118 }View Code