• 模拟101 题解


    A. 五子棋

    简单模拟。

    注意获胜条件有四种情况不是三种

    B. 迷宫

    对于每个点封掉$d$条路。

    考虑反向$dijkstra$跑最短路。

    对于每个元素$i$,当第$d+1$次取出时视作$dis(i,n)$,更新相邻的点。

    C. 三华聚顶

    考场上的思路是,求出一个数组表示$i$步之后形成一个极大连续的用掉的气的区间$[l,r]$的概率。

    根据这个数组,可以直接概率乘当前步的贡献统计答案,然而问题似乎并没有那么简单。

    所以颓了$std$,顺便压了压行,其中英文的部分是原有的注释。

    大致思路是类似的,仍然要考虑每个连续的区间。

    一些理解在$std$的中文注释。

     1 #include<algorithm>
     2 #include<cstdio>
     3 #include<iostream>
     4 #include<vector>
     5 using namespace std;
     6 const int N=205;
     7 long double C[N][N];// binomial coefficient
     8 struct Stat{ // contains stats about a random variable
     9     double sum_,cnt_;
    10     Stat():sum_(0),cnt_(0){}
    11     double E(){
    12         if(cnt_==0) return 0;    
    13         return sum_/cnt_;
    14     }
    15     void AddInfo(double expected,double cnt){
    16         sum_+=expected*cnt;
    17         cnt_+=cnt;
    18     }
    19 }w[N][N],dp[N][N];
    20 int n,g,t;
    21 long double cap_avg(int x,int y,int upper){
    22     if(upper>n) return 0;
    23     return (x+y+1.0)/2;
    24 }
    25 int main(){
    26     cin>>n>>g>>t;
    27     vector<int> c(n+1);
    28     for(int i=1;i<=n;++i) cin>>c[i],c[i]=min(c[i],g); // tables larger than g don't make sense
    29     sort(c.begin()+1,c.end());
    30     c.resize(t+n+1,g); // add virtual tables that catch overflow
    31     int m=c.size();
    32     for(int i=0;i<=t;++i) for(int j=C[i][0]=1;j<=i;++j) C[i][j]=C[i-1][j]+C[i-1][j-1];
    33     //w[i][j] has the statistics of filling up interval [i, j) with customers conditioned upon
    34     //*no one else* coming to the restaurant. Tables are numbered from 0 in ascending order.
    35     for(int i=m-1;~i;--i){
    36         w[i][i].AddInfo(0,1); // empty interval can be occupied in only one way
    37         for(int j=i+1;j<m;++j) if(i+t>=j){ // only process intervals of length <= t
    38             for(int k=i;k<j;++k){
    39                 //merge [i,k) and [k+1,j) by occupying table k 
    40                 long double cnt=w[i][k].cnt_*w[k+1][j].cnt_*(c[k+1]-c[i])*C[j-i-1][k-i];//j-i为区间长度 其中规定第k个最后一个出现 以保证不重 在前j-i-1个精中选择k-i个给左半边气,其余的直接分给右半边
    41                 long double expected=w[i][k].E()+w[k+1][j].E()+cap_avg(c[k+1],c[i],k+1);
    42                 w[i][j].AddInfo(expected,cnt);
    43             }
    44         }
    45     }
    46     //dp[i][k] has the statistics of filling up the first i tables with k different groups,
    47     //conditioned upon no one else coming. Some of the first i tables might be empty.
    48     for(int i=0;i<m;++i){//已经处理完的气
    49         if(i<=t) dp[i][i]=w[0][i];
    50         for(int k=0;k<=t;++k) if(dp[i][k].cnt_>0) for(int j=i+1;j<m;++j){//k为当前轮用了多少精 j为转移到多少气
    51             int new_cnt=k+((j-1)-i); //因为第j个不能用 第i个也不能用 所以(j-1)-i为当前一段连续区间中用到了多少个气 也就是精的增加量
    52          //所以newcnt为之后处理了多少个精
    53             if(new_cnt>t) break;
    54             long double expected=dp[i][k].E()+w[i+1][j].E();//用了[i+1,j)的气
    55             long double cnt=dp[i][k].cnt_*w[i+1][j].cnt_*C[new_cnt][k];
    56             dp[j][new_cnt].AddInfo(expected,cnt);
    57             //dp[i][j] 考虑区间[0,i] 其中用到的气分成若干段
    58             //第i个气一定没有被用   j是已经考虑完了j个精
    59         }
    60     }
    61     printf("%.12lf
    ",dp[m-1][t].E());
    62     return 0;
    63 }
  • 相关阅读:
    如何进行简单画图
    缓冲技术
    信号量机制
    进程通信
    中断技术
    操作系统原理-图书主题
    供多处理器系统中的高速缓存同步中使用的转发状态
    js几种escape()解码与unescape()编码
    MySQL 元数据
    MySQL 复制表
  • 原文地址:https://www.cnblogs.com/skyh/p/11799931.html
Copyright © 2020-2023  润新知