【Foreign】Bumb [模拟退火]

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%

 

posted @ 2017-10-03 21:47  BearChild  阅读(409)  评论(0编辑  收藏  举报