11.3 校内模拟赛

总结:

祭考试做出一道期望 dp /se

考试心路历程:

5 min 读完 T1, ahhhhhh,签到题,10 min 写完,一发过大样例。

8:20 开干 T2,期望 dp,读完题,感觉可做。

写了好久,调过样例,写了对拍,一拍就挂,rnm。

调半天,转移写挂 = =

10:10 开 T3

T3 题目好奇怪,为啥开头是 T2 的题目啊,没用,没用,删了。

艹,这花店在哪儿,我家在哪儿,我咋找不到我家!!

读了好几遍,没读懂题,麻了,睡觉。

赛后:为啥我 T3 题目少了一个自然段啊 !!!!

T1 三向城

题面

solution

手摸题目,你发现这是个满二叉树。

然后你会发现,他的层数其实很少。

你还会发现每个节点的父亲就是改节点 / 2

然后你就暴力向上跳就好了 = =

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAX = 35;
int read() {
  int x = 0, f = 1; char c = getchar();
  while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
  while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
  return x * f;
}
int q, Ans;
int get(int x) {
  for (int i = 1; i <= MAX; i++) 
  	if((1 << i) > x) return i;	 
}
signed main(){
  //freopen("city.in", "r", stdin);
  //freopen("city.out", "w", stdout);
  q = read();
  for (int i = 1, x, y; i <= q; i++) {
     x = read(), y = read();
     Ans = 0;
	 int dep_x = get(x), dep_y = get(y);
	 if(dep_x < dep_y) swap(x, y), swap(dep_x, dep_y);
	 while(dep_x != dep_y) {
	   x = x / 2;
	   Ans++, dep_x--;
	 } 	
	 while(x != y) {
	   x = x / 2, y = y / 2;
	   Ans += 2;
	 }
	 cout<<Ans<<"
";
  }
  return 0;
}

T2 灵魂画师

题面

solution

期望 = 概率 * 权值

显然权值就是颜色,考虑怎么计算每个位置变成某个颜色的概率。

不难发现,某个位置变成哪个颜色只与它被选中的次数有关。

(P_{i, j}) 表示 (i) 一个点出现在 (i) 个区间内,被选中 (j) 次的概率。

显然 (P_{i, j} = frac{C_{i}^{j}}{2})

(f_{i, j}) 表示选中 (i) 次,变为颜色 (j) 的概率。

(f_{i + 1, j imes o \% c} += f_{i, j} / c)

(P)(f) 都可以预处理出来。

(Ans = sum_{i = 1}^{i leq n}sum_{j = 0}^{cnt[i]}sum_{o = 0}^{o < c} f_{j, o} imes P_{cnt[i], j} imes o)

code

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 110;
const double eps = 1e-7;
int read() {
  int x = 0, f = 1; char c = getchar();
  while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
  while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
  return x * f;
}
int n, c, k, cnt[MAXN];
double C[MAXN][MAXN], P[MAXN][MAXN], Ans;
void Init_C() {
  C[0][0] = 1;
  for (int i = 1; i <= 100; i++) {
  	C[i][0] = 1;
  	C[i][0] = C[i][0] / 2.0;
  	for (int j = 0; j <= i; j++) {
	   C[i][j] = C[i - 1][j - 1] / 2.0 + C[i - 1][j] / 2.0;
    }
  }
}
void Init_P() {
  P[0][1] = 1;
  for (int i = 0; i <= k; i++) 
    for (int j = 0; j < c; j++) {
      if(P[i][j] <= eps) continue;
	  for (int o = 0; o < c; o++) {
	     P[i + 1][j * o % c] = (P[i + 1][j * o % c] + P[i][j] / c);
	   }	
    }
}
int main(){
  n = read(), c = read(), k = read();
  Init_C(), Init_P();
  for (int i = 1; i <= k; i++) {
    int x = read(), y = read();
    for (int j = x; j <= y; j++) cnt[j]++;
  } 
  for (int i = 1; i <= n; i++) 
  	for (int j = 0; j <= cnt[i]; j++) 
  	  for (int o = 0; o < c; o++) Ans += C[cnt[i]][j] * P[j][o] * o;
  printf("%.3lf
", Ans);
  return 0;
}

T3 香子兰

题面

solution

直接搬 szt 的了 /cy

你看这个数据范围就知道要状压,你看它要求最短路径就得状压最短路。

我们先跑个 (Folyd) 求出两两之间的最短距离。

我们在设两个数组 (f[S][i],g[S][i]) 分别表示以 (1) 作为出发点,已经进行收割/播种的状态为 (S),最后一个点为 (i) 的最短距离,(g) 数组则表示以 (n) 为出发点。

上面这个 (f,g) 数组可以预处理出来。时间复杂度为 (O(2^nn^2)),这个复杂度有点危,我们发现我们不用枚举全部的,我们只需要枚举 (S)(1) 的个数 (≤frac{n−2}{2}+2) 的状态即可。复杂度就被我们优化掉一个 (n)(我们本质还是枚举所有子集,只不过在某些子集只做了 (O(n)) Check )

然后你枚举首先选择哪 (n−2) 个花田收割,设枚举的收割的花田的状态为 (S)

我们考虑收割的过程,考虑怎么把前一半的最短路和后一半的最短路合并起来,那就是,枚举在集合中的点 (i) 和不在集合中的点 (j),设答案为 (res),则:

(res=min{f[S|1][i] + g[M oplus (S|(1<<n−1))][j]+dis[i][j]})
其中 (M) 表示所有点的全集。

这样就保证了 (S) 状态中选中的点一定会在前 (frac{n−2}{2}) 花田里收割,剩余的点在后来收割。

同理,我们考虑播种的过程,其实就是反过来,我们再设一个播种的答案 (ans),则

(ans=min{g[S|1][i]+f[M oplus (S|(1<<n−1))][j]+dis[i][j]})

最终答案就是 (min{res+ans})

这个直接上搜索就行,控制一下搜索上限,可以控制复杂度为 (O(2^{frac{n−2}{2}}frac{n−2}{2}^2))

code

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 21;
const int INF = 0x3f3f3f3f3f;
int read() {
  int x = 0, f = 1; char c = getchar();
  while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
  while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
  return x * f;
}
int n, m, dis[MAXN][MAXN], N, M, Ans = 0x3f3f3f3f;
int f[MAXN][(1 << 20) - 1], g[MAXN][(1 << 20) - 1];
void Init_dis() {
  for (int i = 1; i <= n; i++) dis[i][i] = 0;
  for (int k = 1; k <= n; k++) 
    for (int i = 1; i <= n; i++) 
      for (int j = 1; j <= n; j++) 
        dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
void Init_F() {
  memset(f, 0x3f, sizeof f);
  f[1][1] = 0;
  for (int s = 0; s < (1 << n); s++) {
  	int cnt = 0;
  	for (int k = 1; k <= n; k++) if(s & (1 << k - 1)) cnt++;
	if (cnt > N + 2) continue; 
    for (int i = 1; i <= n; i++) {
      if(!(s & (1 << i - 1))) continue;
	  for (int j = 1; j <= n; j++) {
	  	if(s & (1 << j - 1)) continue;
	    f[j][s | (1 << j - 1)] = min(f[j][s | (1 << j - 1)], f[i][s] + dis[i][j]);
	  }
	}
  }
}
void Init_G() {
  memset(g, 0x3f, sizeof g);
  g[n][1 << n - 1] = 0;
  for (int s = 0; s < (1 << n); s++) {
  	int cnt = 0;
  	for (int k = 1; k <= n; k++) if(s & (1 << k - 1)) cnt++;
  	if(cnt > N + 2) continue;
  	for (int i = 1; i <= n; i++) { 
  	  if(!(s & (1 << i - 1))) continue;
  	  for (int j = 1; j <= n; j++) {
  	    if(s & (1 << j - 1)) continue;
		g[j][s | (1 << j - 1)] = min(g[j][s | (1 << j - 1)], g[i][s] + dis[i][j]);	 
	  }
	}
  } 
}
int In[MAXN], Out[MAXN], Incnt, Outcnt;
void dfs(int s, int pos, int cnt) {
   if(cnt > N) return ;
   if(pos == n) {
     if(cnt != N) return ;
     int ret_1 = INF, ret_2 = INF;
     for (int i = 1; i <= Incnt; i++) {
       for (int j = 1; j <= Outcnt; j++) {
       	 int x = In[i], y = Out[j];
       	 ret_1 = min(ret_1, f[x][s | 1] + g[y][(s | 1) ^ M] + dis[x][y]);
       	 ret_2 = min(ret_2, g[x][s | (1 << n - 1)] + f[y][(s | (1 << n - 1)) ^ M] + dis[x][y]);
	   }
	 }
	 Ans = min(Ans, ret_1 + ret_2);
     return ;	 
   }
   In[++Incnt] = pos;
   dfs(s | (1 << pos - 1), pos + 1, cnt + 1);
   Incnt--;
   Out[++Outcnt] = pos;
   dfs(s, pos + 1, cnt);
   Outcnt--;
}
int main(){
  n = read(), m = read();
  N = (n - 2) / 2, M = (1 << n) - 1;
  memset(dis, 0x3f, sizeof dis);
  for (int i = 1, u, v, w; i <= m; i++) {
  	 u = read() + 1, v = read() + 1, w = read();
  	 dis[u][v] = dis[v][u] = min(dis[u][v], w);
  }
  Init_dis();
  if(n == 3) {
  	 cout<<(dis[1][2] + dis[2][3]) * 2;
  	 return 0;
  }
  Init_F(), Init_G();
  dfs(0, 2, 0);
  cout<<Ans;
  return 0;
}
原文地址:https://www.cnblogs.com/Arielzz/p/15504838.html