1. 程式人生 > >【Foreign】Bumb [模擬退火]

【Foreign】Bumb [模擬退火]

ear cloc hid 變化 == tchar 個數 main ron

Bumb

Time Limit: 20 Sec Memory Limit: 512 MB

Description

  技術分享

Input

  技術分享

Output

  技術分享

Sample Input

  4
  1 5 1 4

Sample Output

  5

HINT

  技術分享

Solution

  首先,我們對於一個已知的k,可以O(n)得到Ans,這樣就有60%了。

  那麽怎麽做90%呢?老老實實寫O(nlogn)是不可能的!模擬退火美滋滋!

  傳授一點人生的經驗吧:寫個對拍用於調參,由於這種題不能很單峰,顯然溫度變化設大一點比較容易正確,無限running + 卡時即可。

  是的,沒有錯!BearChild就這樣拿到了90%!

  我們來考慮100%怎麽做,顯然復雜度O(n)。我們把( a[i - 1], a[i] ]看作若幹個區間掛在數軸上。

  然後考慮k:1->m對於答案的變化。顯然可以記錄cnt表示k包含的區間個數,以及sum和,這樣就可以做完啦!

Code

技術分享
 1 #include<iostream>    
 2 #include<string>    
 3 #include<algorithm>    
 4 #include<cstdio>    
 5 #include<cstring>    
 6
#include<cstdlib> 7 #include<cmath> 8 #include<vector> 9 #include<ctime> 10 using namespace std; 11 typedef long long s64; 12 13 const int ONE = 1000005; 14 const s64 INF = 1e18; 15 16 int n, m; 17 int a[ONE]; 18 int Now, A; 19 s64 Ans = INF; 20 21 int get()
22 { 23 int res=1,Q=1;char c; 24 while( (c=getchar())<48 || c>57 ) 25 if(c==-)Q=-1; 26 res=c-48; 27 while( (c=getchar())>=48 && c<=57 ) 28 res=res*10+c-48; 29 return res*Q; 30 } 31 32 void TimeE() 33 { 34 if((double)clock() / CLOCKS_PER_SEC > 0.97) 35 { 36 printf("%lld", Ans); 37 exit(0); 38 } 39 } 40 41 s64 Get(int x, int y) 42 { 43 TimeE(); 44 if(x <= y) return y - x; 45 return y + m - x; 46 } 47 48 s64 Judge(int k) 49 { 50 s64 res = 0; 51 for(int i = 2; i <= n; i++) 52 res += min(Get(a[i - 1], a[i]), 1 + Get(k, a[i])); 53 Ans = min(Ans, res); 54 return res; 55 } 56 57 double Random() {return rand() / (double)RAND_MAX;} 58 void SA(double T) 59 { 60 Now = m / 2; 61 while(T >= 1) 62 { 63 A = Now + (int)(T * (Random() * 2 - 1)); 64 if(A < 1 || A > m) A = T * Random(); 65 s64 dE = Judge(A) - Judge(Now); 66 if(dE < 0) Now = A; 67 T *= 0.92; 68 } 69 } 70 71 int main() 72 { 73 n = get(); m = get(); 74 for(int i = 1; i <= n; i++) 75 a[i] = get(); 76 if(n > 3000) {for(;;)SA(m); return 0;} 77 78 for(int i = 1; i <= m; i++) 79 Ans = min(Ans, Judge(i)); 80 81 printf("%lld", Ans); 82 }
模擬退火 90% 技術分享
 1 #include<iostream>    
 2 #include<string>    
 3 #include<algorithm>    
 4 #include<cstdio>    
 5 #include<cstring>    
 6 #include<cstdlib>
 7 #include<cmath>
 8 #include<vector>
 9 using namespace std;  
10 typedef long long s64;
11 
12 const int ONE = 1000005;
13 const s64 INF = 1e18;
14 
15 int n, m;
16 int a[ONE];
17 int L[ONE];
18 vector <int> R[ONE];
19 s64 Ans;
20 
21 int get()
22 {
23         int res=1,Q=1;char c;
24         while( (c=getchar())<48 || c>57 ) 
25         if(c==-)Q=-1; 
26         res=c-48;     
27         while( (c=getchar())>=48 && c<=57 )
28         res=res*10+c-48;    
29         return res*Q;
30 }
31 
32 int Get(int x, int y)
33 {
34         if(x <= y) return y - x;
35         return y + m - x;
36 }
37 
38 int main()
39 {
40         n = get();    m = get();
41         for(int i = 1; i <= n; i++)
42             a[i] = get();
43         
44         for(int i = 2; i <= n; i++)
45         {
46             Ans += Get(a[i - 1], a[i]);
47             L[a[i - 1]]++, R[a[i]].push_back(a[i - 1]);
48         }
49         
50         s64 sum = Ans, cnt = 0;
51         
52         for(int i = 2; i <= n; i++)
53             if(a[i - 1] > a[i])
54                 sum -= m - a[i - 1], cnt++;
55         
56         for(int k = 2; k <= m; k++)
57         {
58             int len = R[k - 1].size();
59             cnt = cnt + L[k - 2] - len;
60             sum -= cnt;
61             for(int i = 0; i < len; i++)
62                 sum += Get(R[k - 1][i], k - 1) - 1;
63             Ans = min(Ans, sum);
64         }
65         
66         printf("%lld", Ans);
67 }
正解 100%

【Foreign】Bumb [模擬退火]