首页 > 其他 > 详细

Rockethon 2015

时间:2015-02-13 00:02:50      阅读:494      评论:0      收藏:0      [点我收藏+]

A Game
题意:A,B各自拥有两堆石子,数目分别为n1, n2,每次至少取1个,最多分别取k1,k2个, A先取,最后谁会赢。

分析:显然每次取一个是最优的,n1 > n2时,先手赢。

代码:

技术分享
 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define esp 1e-14
 5 #define lson   l, m, rt<<1
 6 #define rson   m+1, r, rt<<1|1
 7 #define sz(x) ((int)((x).size()))
 8 #define pf(x) ((x)*(x))
 9 #define pb push_back
10 #define pi acos(-1.0)
11 #define in freopen("solve_in.txt", "r", stdin);
12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
14 #define inf 0x0f0f0f0f
15 using namespace std;
16 typedef long long LL;
17 typedef unsigned US;
18 typedef pair<int, int> PII;
19 typedef map<PII, int> MPS;
20 typedef MPS::iterator IT;
21 
22 int main() {
23 //    in
24    int n1, n2, k1, k2;
25    cin >> n1 >> n2 >> k1 >> k2;
26    puts(n1 > n2 ? "First" : "Second");
27 
28 
29 
30 
31     return 0;
32 }
View Code

 

B1, B2 Permutations

题意:给定排列长度 n <= 50, 技术分享,要求输出字典序第m大的排列,同时使得f(p)最大。

分析:

首先肯定的是应该从小到大,将每个数往剩余位置的两边放。反证法,如果将较小的放在中间,那么被各个区间包含的次数会比较多,结果会比较小,而将小的放在两边结果至少不会变小。

所以最多2^(n-1)个可能值,首先考虑1的放置,如果m > 2^(n-2)则放置在末尾,其他数同样考虑。

代码:

技术分享
 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define esp 1e-14
 5 #define lson   l, m, rt<<1
 6 #define rson   m+1, r, rt<<1|1
 7 #define sz(x) ((int)((x).size()))
 8 #define pf(x) ((x)*(x))
 9 #define pb push_back
10 #define pi acos(-1.0)
11 #define in freopen("solve_in.txt", "r", stdin);
12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
14 #define inf 0x0f0f0f0f
15 using namespace std;
16 typedef long long LL;
17 typedef unsigned US;
18 typedef pair<int, int> PII;
19 typedef map<PII, int> MPS;
20 typedef MPS::iterator IT;
21 
22 int main() {
23 
24     vector<int> ans(55);
25     int n, m;
26     cin >> n >> m;
27     int l = 1, r = n;
28     for(int i = (n-1); i > 0; i--){
29         if(m <= (1<<(i-1))) {
30             ans[l++] = n-i;
31         }else {
32             ans[r--] = n-i;
33             m -= (1<<(i-1));
34         }
35     }
36     ans[l] = n;
37     for(int i = 1; i <= n; i++)
38         printf("%d ", ans[i]);
39     return 0;
40 }
View Code

 

C Second price auction

题意:n个区间(2 <= n <= 5), [Li, Ri](Ri <= 10000),每个区间中随机选出一个整数,求第二大的数的数学期望。

分析:

比赛时做的比较复杂,但还是通过了。具体分为两种情况,最大值唯一和不唯一。

最大值唯一时:

用st表示此时除开最大值的是那些区间,然后dp[i][st]表示这些区间中最大值为i时的概率。

最大值不唯一:

只需要枚举那些区间为最大值,及最大值,计算期望即可。

技术分享
  1 #include <bits/stdc++.h>
  2 #define pb push_back
  3 #define mp make_pair
  4 #define esp 1e-14
  5 #define lson   l, m, rt<<1
  6 #define rson   m+1, r, rt<<1|1
  7 #define sz(x) ((int)((x).size()))
  8 #define pf(x) ((x)*(x))
  9 #define pb push_back
 10 #define pi acos(-1.0)
 11 #define in freopen("solve_in.txt", "r", stdin);
 12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
 13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
 14 #define inf 0x0f0f0f0f
 15 using namespace std;
 16 typedef long long LL;
 17 typedef unsigned US;
 18 typedef pair<int, int> PII;
 19 typedef map<PII, int> MPS;
 20 typedef MPS::iterator IT;
 21 const int maxn = 10000 + 10;
 22 
 23 double dp[maxn][(1<<5)+2];
 24 int L[10], R[10];
 25 int n;
 26 double getProb(int st, int m) {
 27     vector<int> comp;
 28     for(int i = 0; i < n; i++) if(st&(1<<i))
 29             comp.pb(i);
 30     int nn = sz(comp);
 31     double res = 0.0;
 32     for(int x = 1; x < (1<<nn); x++) {
 33 //        vector<int> tmp;
 34         double tmpPro = 1.0;
 35         int ok = 1;
 36         for(int j = 0; j < nn; j++) if(x&(1<<j)) {
 37 //            tmp.pb(comp[j]);
 38 //            cout << L[comp[j]] << ‘ ‘ << R[comp[j]] << endl;
 39                 if(m < L[comp[j]] || m > R[comp[j]]) {
 40                     ok = 0;
 41 //                    bug(1)
 42                     break;
 43                 }
 44                 tmpPro *= 1.0/(R[comp[j]]-L[comp[j]] + 1);
 45 
 46             } else {
 47                 if(m <= L[comp[j]]) {
 48                     ok = 0;
 49                     break;
 50                 }
 51                 tmpPro *= 1.0*(min(R[comp[j]]+1, m)-L[comp[j]])/(R[comp[j]]-L[comp[j]] + 1);
 52             }
 53         if(ok) {
 54 //                cout << tmpPro << endl;
 55             res += tmpPro;
 56         }
 57     }
 58     return res;
 59 }
 60 int main() {
 61 //    in
 62     cin >> n;
 63     int mx = 0, mi = inf;
 64     for(int i = 0; i < n; i++) {
 65         cin >> L[i] >> R[i];
 66         mi = min(mi, L[i]);
 67         mx = max(mx, R[i]);
 68     }
 69     for(int i = 1; i < (1<<n); i++) {
 70         for(int j = mi; j <= mx; j++)
 71             dp[j][i] = getProb(i, j);
 72     }
 73 //    cout << getProb(5, 7) << endl;
 74 //    cout << dp[7][5] << endl;
 75     double ans = 0.0;
 76     int mask = (1<<n)-1;
 77     for(int k = 0; k < n; k++) {
 78         for(int l = mi; l < R[k]; l++) {
 79 //            if(k == 1) cout << l << ‘ ‘ << dp[l][mask^(1<<k)] << endl;
 80             ans += dp[l][mask^(1<<k)]*l*(R[k]-max(L[k]-1, l))/(R[k]-L[k]+1);
 81         }
 82     }
 83 //    cout << ans << endl;
 84     for(int i = mi; i <= mx; i++) {
 85         for(int st = 1; st < (1<<n); st++) {
 86             int ok = 1;
 87             double tmp = 1.0;
 88             for(int x = 0; x < n; x++) if((st&(1<<x))) {
 89 //                    ct++;
 90                     if(i < L[x] || i > R[x]) {
 91                         ok = 0;
 92                         break;
 93                     }
 94                     tmp *= 1.0/(R[x]-L[x]+1);
 95                 } else {
 96                     if(i <= L[x]) {
 97                         ok = 0;
 98                         break;
 99                     }
100                     tmp *= 1.0*(min(R[x]+1,i)-L[x])/(R[x]-L[x]+1);
101                 }
102             if(ok && __builtin_popcount(st) >= 2) {
103                 ans += tmp*i;
104             }
105         }
106     }
107     printf("%.12f\n", ans);
108     return 0;
109 }
View Code

 

D1, D2 Constrained Tree

题意:先序遍历的方式给二叉树标号,一些限制描述:ai bi LEFT or ai bi RIGHT表示bi位于ai的左子树或右子树,构造一棵满足条件的二叉树,中序遍历输出结点编号。

分析:对输入的描述处理,maxL[i]表示位于i结点左子树的点的最大编号,minR[i],maxR[i],表示i右子树结点最小和最大编号。

那么构造时,dfs(rt, must, no)记录rt为根的子树的3个信息,rt, must表示必须包含的点,no表示结点编号不能超过,对于根为rt的子树,其maxL[rt] < minR[rt],并且当

进行构造时,要用maxR[rt]更新must。

技术分享
 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define esp 1e-14
 5 #define lson   l, m, rt<<1
 6 #define rson   m+1, r, rt<<1|1
 7 #define sz(x) ((int)((x).size()))
 8 #define pf(x) ((x)*(x))
 9 #define pb push_back
10 #define pi acos(-1.0)
11 #define in freopen("solve_in.txt", "r", stdin);
12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
14 #define inf 0x0f0f0f0f
15 using namespace std;
16 typedef long long LL;
17 typedef unsigned US;
18 typedef pair<int, int> PII;
19 typedef map<PII, int> MPS;
20 typedef MPS::iterator IT;
21 const int maxn = 1000000 + 10;
22 const int maxm = 100000  + 10;
23 int a[maxm], b[maxm], c[maxm];
24 int maxL[maxn], maxR[maxn], minR[maxn];
25 vector<int> ans;
26 int solve(int rt, int must, int no){
27     if(must < maxR[rt])
28         must = maxR[rt];
29     if(must >= no) {
30         puts("IMPOSSIBLE");
31         exit(0);
32     }
33     int last = rt;
34     if(maxL[rt])
35         last = solve(rt+1, maxL[rt], minR[rt] ? minR[rt] : no);
36     if(!last) {
37         puts("IMPOSSIBLE");
38         exit(0);
39     }
40     ans.pb(rt);
41     if(must >= last+1)
42         return solve(last+1, must, no);
43     return last;
44 }
45 int main(){
46 //    in
47     int n, m;
48     cin >> n >> m;
49     for(int i = 0; i < m; i++){
50         static char s[10];
51         scanf("%d%d%s", a+i, b+i, s);
52         if(s[0] == L) maxL[a[i]] = max(maxL[a[i]], b[i]);
53         else {
54             maxR[a[i]] = max(maxR[a[i]], b[i]);
55             if(!minR[a[i]] || b[i] < minR[a[i]])
56             minR[a[i]] = b[i];
57         }
58         if(a[i] >= b[i] || (minR[a[i]] && maxL[a[i]] >= minR[a[i]]))
59         {
60             puts("IMPOSSIBLE");
61             return 0;
62         }
63     }
64     solve(1, n, n+1);
65     for(int x: ans)
66         printf("%d ", x);
67     return 0;
68 }
View Code

 

E1, E2 Subarray Cuts

题意:一个长度为n的数组,依次选取连续的k部分( k >= 2),si表示第i部分的和,要求 技术分享最大。

分析:官方题解对于E1的解法用到了另一种结论,便是只需要考虑选取m个部分,m <= k, ( + s1 - 2·s2 + 2·s3 - 2·s4 + …) and ( - s1 + 2·s2 - 2·s3 + 2·s4 - …)的大小,且剩下的没有选取的元素>=k-m即可。采用dp即可解决,dp[i][sign][first][last][unused][max], 表示从第i个元素开始,选取max个部分的最大值。

对于E2有另一种解法,技术分享

f(i, j, c1, c2) = max(...   ± (sj -1 - sj -2)±c2(sj - sj - 1)  ±  c1 (0 - sj)...),  选取ai作为sj的一部分时,

f(i, j, c1, c2) = max(...   ± (sj -1 - sj -2)±c2(sj - sj - 1)  ±  c1 (0 - sj)...)

max(...   ± (sj -1 - sj -2)±c2(0- sj - 1)  ±  c2sj+c1 (0 - sj)...)

= max(...   ± (sj -1 - sj -2)±c2(0- sj - 1)  ±  (c2-c1)ai...) ,

f[c1][c2][k]表示从第i个往后选取sk时的最大值,g[c1][k] 表示max(f[c1][c2][k]),即当前选取sk后最大值,

更新时,f[c1][c2][k] = max(f[c1][c2][k], g[c1][k-1]) + (c2-c1)*a[k]。

虽然dp时没有确定各项前的符号,但是绝对值会是>=0, 因此最后得到最大值一定是将前面的c1, c2一定使得各项为>=0的,所以使能够得到最大值的。

题解看了不是很明白,上面的思路属于Petr的代码的,看了觉得理解了就将其按照理解写了一下。

 

代码:

技术分享
 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define esp 1e-14
 5 #define lson   l, m, rt<<1
 6 #define rson   m+1, r, rt<<1|1
 7 #define sz(x) ((int)((x).size()))
 8 #define pf(x) ((x)*(x))
 9 #define pb push_back
10 #define pi acos(-1.0)
11 #define in freopen("solve_in.txt", "r", stdin);
12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
14 #define inf 0x0f0f0f0f
15 using namespace std;
16 typedef long long LL;
17 typedef unsigned US;
18 typedef pair<int, int> PII;
19 typedef map<PII, int> MPS;
20 typedef MPS::iterator IT;
21 const int maxn = 30000 + 10;
22 const int maxm = 200 + 10;
23 int a[maxn], f[2][2][maxm], g[2][maxm];
24 int main() {
25 //    inC
26     int n, k;
27     cin >> n >> k;
28     for (int i = 1; i <= n; i++) scanf("%d", a+i);
29     for(int i = 0; i < maxm; i++) for(int j = 0; j < 2; j++) {
30             g[j][i] = -inf;
31             for(int u = 0; u < 2; u++)
32                 f[u][j][i] = -inf;
33         }
34 
35 
36     g[0][0] = g[1][0] = 0;//init by 0
37     for (int cur = 1; cur <= n; ++cur) {
38         for (int u = 1; u <= k; u++)
39             for (int now = 0; now < 2; now++)
40                 for (int pre = 0; pre < 2; pre++) {
41                     int e = (u == 1 ? 0 : 2*pre-1);
42                     e += (u == k ? 0 : 1-2*now);
43                     f[now][pre][u] =  max(f[now][pre][u], g[pre][u-1]) + e*a[cur];
44                 }
45         for(int now = 0; now < 2; now++)
46             for(int u = 1; u <= k; u++) {
47                 g[now][u] = max(g[now][u], max(f[now][0][u], f[now][1][u]));
48             }
49     }
50     printf("%d\n", max(g[0][k], g[1][k]));
51     return 0;
52 }
View Code

 

F1,F2 Scaygerboss

题意:males,female只雄蜂,雌蜂,及蜂王,位于一个n*m的迷宫,每只蜂可以移动到相邻位置上,时间为t,有障碍物的格子不能移动上去,要求能否每一只蜂和另外一只性别不同的蜂处于同一格子,且移动的最大时间最小。

分析:首先根据males和females的数目,将蜂王看做雌性或雄性(少的那一种),如果两种数目仍然不相等,则显然不会满足条件。

然后,构建网络流图,(src, sink), src->males,容量为1,females-sink,容量为1,然后将每个空格子拆成两点,u,v,males->u, 及v->females表示占领该格子,u->v容量为1,当然为了求最小时间,需二分可能的时间,只有当males,females到相应格子时间<=二分值时才连相应的边,最大流的值 == males时表示可行。

 

代码:

技术分享
  1 #include <bits/stdc++.h>
  2 #define pb push_back
  3 #define mp make_pair
  4 #define esp 1e-14
  5 #define lson   l, m, rt<<1
  6 #define rson   m+1, r, rt<<1|1
  7 #define sz(x) ((int)((x).size()))
  8 #define pf(x) ((x)*(x))
  9 #define pb push_back
 10 #define pi acos(-1.0)
 11 #define in freopen("solve_in.txt", "r", stdin);
 12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
 13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
 14 #define inf 0x0f0f0f0f
 15 #define INF 0x0f0f0f0f0f0f0f0f
 16 using namespace std;
 17 typedef long long LL;
 18 typedef unsigned US;
 19 typedef pair<int, int> PII;
 20 typedef map<PII, int> MPS;
 21 typedef MPS::iterator IT;
 22 
 23 const int maxn = 25;
 24 const int maxm = 3000;
 25 
 26 char maze[maxn][maxn];
 27 int g[maxn*maxn][maxn*maxn];
 28 int n, m, N, M;
 29 int src, sink;
 30 
 31 LL ans;
 32 
 33 struct Node {
 34     int r, c, t;
 35     Node() {}
 36     Node(int r, int c, int t):r(r), c(c), t(t) {}
 37 };
 38 vector<Node> males, fmales;
 39 
 40 struct Edge {
 41     int u, v, c;
 42     Edge() {}
 43     Edge(int u, int v, int c):u(u), v(v), c(c) {}
 44 };
 45 
 46 
 47 struct MaxFlow {
 48     int n, m;
 49     int Now[maxm], Dfn[maxm], Cur[maxm];
 50 
 51     vector<Edge> edges;
 52     vector<int> G[maxm];//border !
 53 
 54     void init(int n) {
 55         this->n = n;
 56         for(auto &x: G)
 57             x.clear();
 58         edges.clear();
 59     }
 60 
 61     void add(int u, int v, int c) {
 62 //        cout << u << ‘-‘ << v << endl;
 63         edges.pb(Edge(u, v, c));
 64         edges.pb(Edge(v, u, 0));
 65         m = sz(edges);
 66         G[u].pb(m-2);
 67         G[v].pb(m-1);
 68     }
 69 
 70     int ISAP(int s, int flow){
 71         if(s == sink) return flow;
 72         int v, tab = n, now = 0, vary;
 73         int p = Cur[s], &q = Cur[s];
 74         do{
 75             Edge &e = edges[G[s][q]];
 76             if(e.c > 0){
 77                 if(Dfn[s] == Dfn[v = e.v] + 1)
 78                     vary = ISAP(v, min(flow-now, e.c)), now += vary,
 79                     e.c -= vary, edges[G[s][q]^1].c += vary;
 80                 if(Dfn[src] == n) return now;
 81                 if(e.c > 0) tab = min(tab, Dfn[v]);
 82 
 83             }
 84             if(++q == sz(G[s])) q = 0;
 85             if(now == flow) break;
 86         }
 87         while(p != q);
 88         if(now == 0){
 89             if(--Now[Dfn[s]] == 0)
 90                 Dfn[src] = n;
 91             ++Now[Dfn[s] = tab+1];
 92         }
 93         return now;
 94     }
 95     int getAns() {
 96         int flow = 0;
 97         memset(Dfn, 0, sizeof Dfn);
 98         memset(Now, 0, sizeof Now);
 99         memset(Cur, 0, sizeof Cur);
100         Now[0] = n;
101         while(Dfn[src] < n) flow += ISAP(src, inf);
102         return flow;
103     }
104 } solver;
105 
106 int idx(char x, int y) {
107     return x*m+y;
108 }
109 bool cango(int x, int y) {
110     return x >= 0 && x < n && y >= 0 && y < m;
111 }
112 int dx[] = {0, 0, -1, 1};
113 int dy[] = {-1, 1, 0, 0};
114 
115 void calDist() {
116     memset(g, 0x0f, sizeof g);
117     for(int i = 0; i < n*m; i++) g[i][i] = 0;
118     for(int x = 0; x < n; x++)
119         for(int y = 0; y < m; y++) {
120             if(maze[x][y] != .) continue;
121             int u = idx(x, y);
122             for(int k = 0; k < 4; k++) {
123                 int nx = x+dx[k];
124                 int ny = y+dy[k];
125                 if(!cango(nx, ny) || maze[nx][ny] == #) continue;
126                 int v = idx(nx, ny);
127                 g[u][v] = 1;
128             }
129         }
130     for(int k = 0; k < n*m; k++)
131         for(int i = 0; i < n*m; i++)
132             for(int j = 0; j < n*m; j++) {
133                 if(g[i][k] == inf|| g[k][j] == inf)
134                     continue;
135                 g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
136             }
137 }
138 bool check(LL mid) {
139     src = 2*N+2*n*m;
140     sink = src + 1;
141     solver.init(sink+1);
142     for(int j = 0; j < n; j++) for(int k = 0; k < m; k++) {
143             if(maze[j][k] == #) continue;
144 
145             int v = idx(j, k);
146             int id1 = 2*N+v*2;
147             int id2 = id1 + 1;
148             solver.add(id1, id2, 1);
149         }
150 //        bug(1)
151     for(int i = 0; i < N; i++) {
152         int x = males[i].r, y = males[i].c, t = males[i].t;
153         int u = idx(x, y);
154 
155         solver.add(src, i, 1);
156         for(int j = 0; j < n; j++) for(int k = 0; k < m; k++) {
157                 if(maze[j][k] == #) continue;
158                 int v = idx(j, k);
159 //                if(u == v) continue;
160                 int id1 = 2*N+v*2;
161                 int id2 = id1 + 1;
162 //                cout << id1 << id2 << endl;
163 //                cout << u << v << endl;
164                 if(g[u][v] != inf && 1.0*g[u][v]*t <= mid)
165                     solver.add(i, id1, 1);
166             }
167         x = fmales[i].r, y = fmales[i].c, t = fmales[i].t;
168         u = idx(x, y);
169         solver.add(i+N, sink, 1);
170         for(int j = 0; j < n; j++) for(int k = 0; k < m; k++) {
171                 if(maze[j][k] == #) continue;
172                 int v = idx(j, k);
173                 int id1 = 2*N+v*2;
174                 int id2 = id1 + 1;
175                 if(g[u][v] != inf && 1.0*g[u][v]*t <= mid)
176                     solver.add(id2, i+N, 1);
177             }
178     }
179 //    bug(1)
180     return solver.getAns() == N;
181 }
182 int main() {
183 //    in
184 
185     cin >> n >> m >> N >> M;
186 
187     for(int i = 0; i < n; i++) scanf("%s", maze[i]);
188     int ok = 1;
189     int r, c, t;
190     scanf("%d%d%d", &r, &c, &t);
191     r--, c--;
192     if(N-M == 1) {
193         fmales.pb(Node(r, c, t));
194     } else if(M-N == 1) {
195         males.pb(Node(r, c, t));
196     } else {
197         ok = 0;
198     }
199     for(int i = 0; i < N; i++) {
200         scanf("%d%d%d", &r, &c, &t);
201         r--, c--;
202         males.pb(Node(r, c, t));
203     }
204     for(int i = 0; i < M; i++) {
205         int r, c, t;
206         scanf("%d%d%d", &r, &c, &t);
207         r--, c--;
208         fmales.pb(Node(r, c, t));
209     }
210 
211     if(!ok) {
212         puts("-1");
213         return 0;
214     }
215     N = max(N, M);
216     calDist();
217     LL L = 0, R = (LL)1e15;
218 //   cout << check(R) << endl;
219 //bug(1)
220     while(R-L > 0){
221         LL mid = (L+R)>>1;
222 
223         if(check(mid)) R = mid;
224         else L = mid+1;
225     }
226     if(R != (LL)1e15) {
227         printf("%lld\n", R);
228     } else puts("-1");
229     return 0;
230 }
View Code

 

 G1, G2, G3 Inversions problem

题意:给定长度为n的排列,及k,表示每次可以选取一个区间[li, ri]将其中的数位置反转,求进行k次后逆序对的个数的期望值。

分析:

G1 由于n <= 6, k <= 4, 所以可以直接dp,dp[perm][m]表示排列为perm时,进行m次操作后逆序对的期望值,或者直接模拟每次操作也行。

代码:

技术分享
 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define esp 1e-14
 5 #define lson   l, m, rt<<1
 6 #define rson   m+1, r, rt<<1|1
 7 #define sz(x) ((int)((x).size()))
 8 #define pf(x) ((x)*(x))
 9 #define pb push_back
10 #define pi acos(-1.0)
11 #define in freopen("solve_in.txt", "r", stdin);
12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
14 #define inf 0x0f0f0f0f
15 using namespace std;
16 typedef long long LL;
17 typedef unsigned US;
18 typedef pair<int, int> PII;
19 typedef map<PII, int> MPS;
20 typedef MPS::iterator IT;
21 const int maxn = 110;
22 
23 int a[maxn];
24 int l[maxn], r[maxn];
25 double ans;
26 int n, k, cnt;
27 
28 int getInv(int *a) {
29     int res = 0;
30     for(int i = 1; i <= n; i++) for(int j = i+1; j <= n; j++)
31             if(a[i] > a[j]) res++;
32     return res;
33 }
34 void rev(int *src, int *tar, int l, int r) {
35     for(int i = 1; i <= n; i++) tar[i] = src[i];
36     reverse(tar+l, tar+r+1);
37 }
38 void dfs(int y, int *src) {
39     int tar[maxn];
40     if(y == k) {
41         for(int i = 1; i <= n; i++) tar[i] = src[i];
42         ans += getInv(tar);
43         return;
44     }
45     for(int i = 0; i < cnt; i++) {
46         rev(src, tar, l[i], r[i]);
47         dfs(y+1, tar);
48     }
49 }
50 int main() {
51 //    in
52     cin >> n >> k;
53     for(int i = 1; i <= n; i++)
54         scanf("%d", a+i);
55 
56     for(int i = 1; i <= n; i++)
57         for(int j = i; j <= n; j++)
58             l[cnt] = i, r[cnt++] = j;
59     dfs(0, a);
60     for(int i = 0; i < k; i++)
61         ans /= cnt;
62     printf("%.12f\n", ans);
63     return 0;
64 }
View Code

 

G2 n <= 30, k <= 200, 数据增大之后肯定不能计算最终排列中逆序对的个数,然后求期望。

可以考虑原排列中x, y  dp[x][y][k]表示进行k次操作之后,x, y在原数组中的元素依然能保持原顺序的概率。

这样选取区间[l, r],转移时4种情况,

1) 区间不反转x 或 y --------- y < l || x > r || (x < l && y > r) 

2) 区间仅覆盖x----------------l <= x && x <= r && y >r

3) 区间仅覆盖y----------------l <= y && y <= r && x < l

4) 区间覆盖x和y---------------l <= x && x < y && y <= r 

复杂度O(n^4*k)

代码:

技术分享
 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define esp 1e-14
 5 #define lson   l, m, rt<<1
 6 #define rson   m+1, r, rt<<1|1
 7 #define sz(x) ((int)((x).size()))
 8 #define pf(x) ((x)*(x))
 9 #define pb push_back
10 #define pi acos(-1.0)
11 #define in freopen("solve_in.txt", "r", stdin);
12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
14 #define inf 0x0f0f0f0f
15 #define INF 0x0f0f0f0f0f0f0f0f
16 using namespace std;
17 typedef long long LL;
18 typedef unsigned US;
19 typedef pair<int, int> PII;
20 typedef map<PII, int> MPS;
21 typedef MPS::iterator IT;
22 
23 const int maxn = 100 + 10;
24 const int maxm = 2000;
25 double dp[maxn][maxn][maxm];
26 
27 int a[maxn];
28 int n;
29 
30 
31 int main() {
32 //    in
33     int m;
34     scanf("%d%d", &n, &m);
35     for(int i = 1; i <= n; i++) {
36         scanf("%d", a+i);
37     }
38     double ans = 0.0;
39     for(int i = 0; i < maxn; i++) for(int j = 0; j < maxn; j++)
40             dp[i][j][0] = 1;
41     for(int k = 1; k <= m; k++)
42         for(int x = 1; x <= n; x++) for(int y = x+1; y <= n; y++) {
43                 double &res = dp[x][y][k];
44                 for(int l = 1; l <= n; l++) for(int r = l; r <= n; r++)
45                         if((l > y) || (l > x && r < y) || r < x)
46                             res += dp[x][y][k-1];
47                         else if(l <= x && x <= r && y > r)
48                             res += dp[r+l-x][y][k-1];
49                         else if(l <= y && y <= r && x < l)
50                             res += dp[x][r+l-y][k-1];
51                         else if(l <= x && y <= r) res += 1-dp[r+l-y][r+l-x][k-1];
52                 res *= 2.0/(n+1)/n;
53             }
54     for(int i = 1; i <= n; i++) for(int j = i+1; j <= n; j++)
55             if(a[i] > a[j]) ans += dp[i][j][m];
56             else ans += 1-dp[i][j][m];
57     printf("%.12f\n", ans);
58     return 0;
59 }
View Code

 

G3 <= 200,k <= (int)1e9, G3的做法是在上面进行改进的,主要是针对转移部分,计算出转移到dp[x‘][y‘][k-1]的数目。复杂度O(n^3*k)

因为结果会收敛趋于稳定,所以k可取min(k, 1000),但是

改进后代码还是TLE on test 38。估计优化还不够, 对比他人的代码,冗余运算太多。

上一下代码:

技术分享
  1 #include <bits/stdc++.h>
  2 #define pb push_back
  3 #define mp make_pair
  4 #define esp 1e-14
  5 #define lson   l, m, rt<<1
  6 #define rson   m+1, r, rt<<1|1
  7 #define sz(x) ((int)((x).size()))
  8 #define pf(x) ((x)*(x))
  9 #define pb push_back
 10 #define pi acos(-1.0)
 11 #define in freopen("solve_in.txt", "r", stdin);
 12 #define bug(x) printf("Line : %u >>>>>>\n", (x));
 13 #define TL cerr << "Time elapsed: " << (double)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
 14 #define inf 0x0f0f0f0f
 15 #define INF 0x0f0f0f0f0f0f0f0f
 16 using namespace std;
 17 typedef long long LL;
 18 typedef unsigned US;
 19 typedef pair<int, int> PII;
 20 typedef map<PII, int> MPS;
 21 typedef MPS::iterator IT;
 22 
 23 const int maxn = 100 + 10;
 24 const int maxm = 2000;
 25 double dp[maxn][maxn][maxm];
 26 
 27 int a[maxn];
 28 int n;
 29 
 30 
 31 int main() {
 32 
 33     int m;
 34     scanf("%d%d", &n, &m);
 35     m = min(m, 1000);
 36     for(int i = 1; i <= n; i++) {
 37         scanf("%d", a+i);
 38     }
 39     double ans = 0.0;
 40     for(int i = 0; i < maxn; i++) for(int j = 0; j < maxn; j++)
 41             dp[i][j][0] = 1;
 42     for(int k = 1; k <= m; k++)
 43 //        int k = 1;
 44         for(int x = 1; x <= n; x++) for(int y = x+1; y <= n; y++)
 45             {
 46                 double &res = dp[x][y][k];
 47 
 48                 //completely not cover [x, y],
 49                 res += dp[x][y][k-1]*((n-y)*(n-y+1)/2+(x-1)*x/2+(y-x-1)*(y-x)/2);
 50 //                cout << ((n-y)*(n-y+1)/2+(x-1)*x/2+(y-x-1)*(y-x)/2) << endl;
 51 //                cout << res << endl;
 52                 //cover x, not cover y,
 53                 for(int l = 1; l < y; l++) {
 54                     if((l<<1)-x > 0 && (l<<1)-x < y) {
 55                         int cnt = min(y-(l<<1)+x, y-x);
 56                         cnt = min(cnt, min((l<<1)-x, x));
 57                         assert(cnt >= 0);
 58                         res += dp[(l<<1)-x][y][k-1]*cnt;
 59                     }
 60 
 61                     if((l<<1|1)-x > 0 && (l<<1|1)-x < y) {
 62                         int cnt = min(y-(l<<1|1)+x, y-x);
 63                         cnt = min(cnt, min((l<<1|1)-x, x));
 64                         assert(cnt >= 0);
 65                         res += dp[(l<<1|1)-x][y][k-1]*cnt;
 66                     }
 67 
 68                 }
 69                 //cover y, not cover x,
 70                 for(int l = x+1; l <= n; l++) {
 71                     if((l<<1)-y > x && (l<<1)-y <= n) {
 72                         int cnt = min(n+1-(l<<1)+y, n+1-y);
 73 //                        cout << cnt << endl;
 74                         cnt = min(cnt, min((l<<1)-y-x, y-x));
 75                         assert(cnt >= 0);
 76 //                        bug(1)
 77                         res += dp[x][(l<<1)-y][k-1]*cnt;
 78                     }
 79 //                    cout << res << endl;
 80                     if((l<<1|1)-y > x && (l<<1|1)-y <= n) {
 81                         int cnt = min(n+1-(l<<1|1)+y, n+1-y);
 82                         cnt = min(cnt, min((l<<1|1)-y-x, y-x));
 83                         assert(cnt >= 0);
 84                         res += dp[x][(l<<1|1)-y][k-1]*cnt;
 85                     }
 86 //                    cout << res << endl;
 87                 }
 88 //                cout << res << endl;
 89                 //cover [x, y].
 90                 for(int l = 1; l <= n; l++) {
 91                     if((l<<1)-x > 0 && (l<<1)-x <= n
 92                             &&(l<<1)-y > 0 && (l<<1)-y <= n) {
 93 
 94                         int cnt = min(n+1-(l<<1)+y, n+1-y);
 95                         cnt = min(cnt, min((l<<1)-y, y));
 96                         cnt = min(cnt, min(n+1-(l<<1)+x, n+1-x));
 97                         cnt = min(cnt, min((l<<1)-x, x));
 98                         assert(cnt >= 0);
 99 //                        cout << cnt << endl;
100                         res += (1-dp[(l<<1)-y][(l<<1)-x][k-1])*cnt;
101                     }
102                     if((l<<1|1)-x > 0 && (l<<1|1)-x <= n
103                             &&(l<<1|1)-y > 0 && (l<<1|1)-y <= n) {
104                         int cnt = min(n+1-(l<<1|1)+y, n+1-y);
105                         cnt = min(cnt, min((l<<1|1)-y, y));
106                         cnt = min(cnt, min(n+1-(l<<1|1)+x, n+1-x));
107                         cnt = min(cnt, min((l<<1|1)-x, x));
108                         assert(cnt >= 0);
109                         res += (1-dp[(l<<1|1)-y][(l<<1|1)-x][k-1])*cnt;
110                     }
111                 }
112                 res *= 2.0/(n+1)/n;
113             }
114     for(int i = 1; i <= n; i++) for(int j = i+1; j <= n; j++)
115             if(a[i] > a[j]) ans += dp[i][j][m];
116             else ans += 1-dp[i][j][m];
117     printf("%.12f\n", ans);
118     return 0;
119 }
View Code

 

 

 

技术分享
技术分享
技术分享
技术分享

Rockethon 2015

原文:http://www.cnblogs.com/rootial/p/4289327.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!