zoukankan      html  css  js  c++  java
  • 2018.10.06模拟总结

    看是老家的中学出的题目,会不会可爱一点呢?

    嗯,真可爱,可爱的我两道题文件都错了。

    因为最近我把文件输入输出改成#ifndef和#endif的形式了,然后放在了一个函数里,结果敲板子的时候忘调用了……

    鬼知道为啥我T1敲了上去。

     

    T1 rps

      期望得分:20

      实际得分:40

      看了看题,发现这其实构成了一棵满二叉树,但这好像并没有什么用。然后就开始想暴力,可惜的是暴力都不知道怎么写。随便看了看上个厕所,突然发现只要最后的胜者确定了,这个序列就是唯一的,仅仅是没排好序。于是我就开始枚举胜者,再分治判断,然后我就不知怎么的开始犯zz了:如果合法,就直接排序输出,然后break了!我当时不知怎么想的,认为合法的序列就一个,然后又担心时间复杂度,决定找一个就完事……更有乐的是,我排序的时候又怕时间不够,只比较了两个序列的前4个字符……

      所以估分的时候就只敢保证送的那20分。

      正解其实和我的思路一样:枚举最终胜者,判定是否合法,如果合法,就排完序存下来,最后从得到的三个序列中取字典序最小的。排序就像归并排序,所以复杂度O(3 * nlogn)。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = (1 << 20) + 5;
     21 const int base = 100;
     22 inline ll read()
     23 {
     24     ll ans = 0;
     25     char ch = getchar(), last = ' ';
     26     while(!isdigit(ch)) {last = ch; ch = getchar();}
     27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     28     if(last == '-') ans = -ans;
     29     return ans;
     30 }
     31 inline void write(ll x)
     32 {
     33     if(x < 0) x = -x, putchar('-');
     34     if(x >= 10) write(x / 10);
     35     putchar(x % 10 + '0');
     36 }
     37 void MYFILE()
     38 {
     39 #ifndef mrclr
     40   freopen("rps.in", "r", stdin);
     41   freopen("rps.out", "w", stdout);
     42 #endif
     43 }
     44 
     45 int r, p, s, n;
     46 const char c[3] = {'P', 'R', 'S'};
     47 int num[3], a[maxn], ans[3][maxn];
     48 
     49 bool judge(int L, int R, int x)
     50 {
     51     if(L == R)
     52     {
     53         if(--num[x] < 0) return 0;
     54         a[L] = x; return 1;
     55     }
     56     int mid = (L + R) >> 1;
     57     return judge(L, mid, x) && judge(mid + 1, R, ++x > 2 ? 0 : x);
     58 }
     59 void rotate(int L, int R)        //归并排序 
     60 {
     61     if(L == R) return;
     62     int mid = (L + R) >> 1;
     63     rotate(L, mid); rotate(mid + 1, R);
     64     bool flg = 0;
     65     for(int i = L, j = mid + 1; i <= mid; ++i, ++j)
     66         if(a[i] > a[j]) {flg = 1; break;}
     67     if(flg) for(int i = L, j = mid + 1; i <= mid; ++i, ++j)
     68         swap(a[i], a[j]);
     69 }
     70 
     71 void init()
     72 {
     73     num[0] = p; num[1] = r; num[2] = s;
     74 }
     75 
     76 void work(int x)
     77 {
     78     init();
     79     if(judge(1, n, x))
     80     { 
     81         rotate(1, n);
     82         for(int i = 1; i <= n; ++i) ans[x][i] = a[i];
     83     }
     84 }
     85 
     86 int main()
     87 {
     88   MYFILE();
     89   r = read(), p = read(), s = read();
     90   n = r + p + s;
     91   for(int i = 0; i < 3; ++i) ans[i][1] = 'Z';
     92   for(int i = 0; i < 3; ++i) work(i);
     93   for(int i = 1; i <= n; ++i)        //一下繁琐的代码其实就是在找三者中字典序最小的…… 
     94   {
     95     int Min = ans[0][i], pos = 0, pos2 = ans[0][i];
     96       for(int j = 1; j < 3; ++j)
     97       {
     98         if(ans[j][i] < Min) Min = ans[j][i], pos = j;
     99         if(ans[j][i] != pos2) pos2 = -1;
    100       } 
    101     if(pos2 == -1)
    102       {
    103           for(int j = 1; j <= n; ++j) putchar(c[ans[pos][j]]);
    104           enter; return 0;
    105       }
    106   }
    107   printf("IMPOSSIBLE
    ");
    108   return 0;
    109 }
    View Code

    T2 vote

      期望得分:30

      实际得分:0(30)

      0分就是文件的事了……加上后是30.

      一看就不会呀!管他什么期望dp,上去先捡了10分,然后对于1,2测试点,二进制暴力枚举,复杂度O(C(k, n) * C(k / 2, k) * n),代码里面我预处理了从n中取k个的所有情况,所以实际复杂度能更低一点。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 18;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 void MYFILE()
    37 {
    38 #ifndef mrclr
    39   freopen("vote.in", "r", stdin);
    40   freopen("vote.out", "w", stdout);
    41 #endif
    42 }
    43 
    44 int n, k;
    45 db a[maxn];
    46 
    47 int s[1 << maxn], cnt = 0;
    48 int s2[1 << maxn], cnt2 = 0;
    49 void init()
    50 {
    51   for(int i = 0; i < (1 << n); ++i)
    52     {
    53       int x = 0, tp = i;
    54       while(tp)
    55     {
    56       if(tp & 1) x++;
    57       tp >>= 1;
    58     }
    59       if(x == k) s[++cnt] = i;
    60       if(x == (k >> 1)) s2[++cnt2] = i;
    61     }
    62 }
    63 
    64 db ans = 0;
    65 
    66 int main()
    67 {
    68   MYFILE();        //就少了这个! 
    69   n = read(); k = read();
    70   for(int i = 1; i <= n; ++i) scanf("%lf", &a[i]);
    71   if(n == 2) {printf("%.8lf
    ", a[1] * (1 - a[2]) + (1 - a[1]) * a[2]); return 0;}
    72   if(n > 16) {printf("0.500000000
    "); return 0;}
    73   init();
    74   for(int i = 1; i <= cnt; ++i)
    75     {
    76       db Max = 0;
    77       for(int j = 1; j <= cnt2; ++j) if((s[i] & s2[j]) == s2[j]) 
    78     {
    79       db x = 1;
    80       for(int h = 1; h <= n; ++h)
    81         {
    82           if((1 << (h - 1)) & s2[j]) x *= (1 - a[h]);
    83           else if((1 << (h - 1)) & s[i]) x *= a[h];
    84         }
    85       Max += x;
    86     }
    87       ans = max(ans, Max);
    88     }
    89   printf("%.8lf
    ", ans);
    90   return 0;
    91 }
    View Code

      正解其实还是比较好理解的……

      有一个结论,就是先排个序,选出的k个数一定是一个前缀和一个后缀,证明放在最后。

      接下来就比较好想了:我们先做一个n = k的情况:令dp[i][j]表示在选了的长度为 i 的前缀中,用 j 个人投了“好票”的概率,那么dp[i][j] = a[i] * dp[i - 1][j - 1] + (1 - a[i]) * dp[i - 1][j]。

      最终输出dp[n][n / 2]即可。

      对于k != n的情况,我们既然已经知道了肯定是选一个前缀和后缀,那么就dp两次:令pre[i][j]表示在选了的前 i 个人中有 j 个投了“好票”的概率,suf[i][j]表示在选了的后 i 个人中有 j 个人头好票的概率。转移方程和上面几乎一样,就不讲了。

      维护好了这俩,我们再O(n2)枚举一下就行:枚举选了前 x 个人,所以后缀就是k - x个,再枚举在x个人中有h个人投“好票”。然后维护最大值就行了。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a, x) memset(a, x, sizeof(a))
    15 #define rg register
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const db eps = 1e-8;
    20 const int maxn = 2e3 + 5;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 void MYFILE()
    37 {
    38 #ifndef mrclr
    39     freopen("vote.in", "r", stdin);
    40     freopen("vote.out", "w", stdout);
    41 #endif
    42 }
    43 
    44 int n, k;
    45 db a[maxn];
    46 db pre[maxn][maxn], suf[maxn][maxn];
    47 
    48 int main()
    49 {
    50     MYFILE();
    51     n = read(); k = read();
    52     for(int i = 1; i <= n; ++i) scanf("%lf", &a[i]);
    53     sort(a + 1, a + n + 1);
    54     pre[0][0] = 1;
    55     for(int i = 1; i <= n; ++i)
    56     {
    57         for(int j = 1; j <= i; ++j)
    58             pre[i][j] = a[i] * pre[i - 1][j - 1] + (1 - a[i]) * pre[i - 1][j];
    59         pre[i][0] = (1 - a[i]) * pre[i - 1][0];
    60     }
    61     suf[n + 1][0] = 1;
    62     for(int i = n; i; --i)
    63     {
    64         for(int j = 1; j <= n - i + 1; ++j)
    65             suf[i][j] = a[i] * suf[i + 1][j - 1] + (1 - a[i]) * suf[i + 1][j];
    66         suf[i][0] = (1 - a[i]) * suf[i + 1][0];
    67     }
    68     db ans = 0;
    69     for(int L = 0; L <= k; ++L)        //pre : 0 ~ k
    70     {
    71         int R = n + 1 + L - k; 
    72         db Max = 0;
    73         for(int i = 0; i <= (k >> 1); ++i) Max += pre[L][i] * suf[R][(k >> 1) - i];
    74         ans = max(ans, Max);
    75     }
    76     printf("%.8lf
    ", ans);
    77     return 0;
    78 }
    View Code

    证明来啦:

      首先是感性理解:假设有两个人,一个人投“好票”的概率很大,一个人投“好票”的概率很小,那么他们两人投平票的概率就很大。完了。

      数学证明(Ssy大佬讲的,巨):我们假设[1, L]和[R, n]已经都选了,也就是说我们要证明下一个数应该在L +1处或是R - 1处取到。

      dp方程可以写出来:dp[i][j] = a[i] * dp[L][j - 1] + (1 - a[i]) * dp[L][j]      i∈[L + 1, R - 1]

      因为对于dp过的结果不会改变,不妨令A = dp[L][j - 1], B = dp[L][j],

      则dp[i][j] = A * a[i] + B * (1 - a[i]) = (A - B) * a[i] + B

      可见这是一个一次函数,那么自然在端点处取得最值。

    T3 factory

      期望得分:10

      实际得分:0(20)

      我再也不会忘写文件了。

      看者数据范围我就觉得是最小割,结果图怎么也建不出来,最后搞了一个只能过样例的错误建图方法,自然是gg了。

      题解没看懂,大概是用二分图证明任意一个极大匹配都是完美匹配,然后状压dp求解。

    今天是真有点惨,希望明天能扳回来点儿……

  • 相关阅读:
    一致性哈系算法
    进程通信,线程通信,同步方式
    token的作用
    PHP与web 页面交互
    PHP !!
    Vue局部组件和全局组件
    vue父子组件之间的通信
    Spring Cloud 微服务架构学习笔记与示例
    feign中开启熔断的书写步骤
    使用springboot配置和注入数据源属性的方法和步骤
  • 原文地址:https://www.cnblogs.com/mrclr/p/9747676.html
Copyright © 2011-2022 走看看