最新文章

[BZOJ4318]OSU! 题解

[BZOJ4318]OSU! 题解

题目地址:BZOJ:Problem 4318. — OSU!

题目描述

osu 是一款群众喜闻乐见的休闲软件。
我们可以把osu的规则简化与改编成以下的样子:
一共有n次操作,每次操作只有成功与失败之分,成功对应1,失败对应0,n次操作对应为1个长度为n的01串。在这个串中连续的 X个1可以贡献X^3 的分数,这x个1不能被其他连续的1所包含(也就是极长的一串1,具体见样例解释)
现在给出n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留1位小数。

题意简述

有一个由随机变量组成的数列,对于数列中的变量$X_i$,它的取值有$p_i$的概率为1,$1-p_i$的概率为0,一段连续的1对数列得分的贡献是该段长度的立方,一个数列的得分是所有连续的1段的贡献之和。求数列的期望分数。

输入输出格式

输入格式:
第一行有一个正整数n,表示操作个数。接下去n行每行有一个[0,1]之间的实数,表示每个操作的成功率。

输出格式:
只有一个实数,表示答案。答案四舍五入后保留1位小数。

输入输出样例

输入样例#1:

3
0.5
0.5
0.5 

输出样例#1:

6.0

说明

【样例说明】
000分数为0,001分数为1,010分数为1,100分数为1,101分数为2,110分数为8,011分数为8,111分数为27,总和为48,期望为48/8=6.0
N<=100000

题解

参考资料:BZOJ 4318 OSU! 期望DP – 世界 – CSDN博客
令随机变量$Y_i$表示到第$i$位为止连续的后缀1的期望长度,$f(i)$为到第$i$位为止总得分的期望值。加入第$i$位后,对期望的贡献值为$f(i) – f(i-1) = p_i \{\mathrm{E}[(Y_{i-1}+1)^3] – \mathrm{E}(Y_{i-1}^3)\} = p_i [3\mathrm{E}(Y_{i-1}^2) + 3\mathrm{E}(Y_{i-1}) + 1]$。
只需要维护出$Y$和$Y^2$的期望值就可以递推得到总得分的期望。
$Y$的期望分类讨论,$X_i=0$时$Y_i=0$,$X_i=1$时$Y_i=Y_{i-1}+1$,因此$\mathrm{E}(Y_i) = p_i[\mathrm{E}(Y_{i-1})+1]$。
$Y^2$的期望也可以用与上面类似的方法推,$X_i=0$时$Y^2_i=0$,$X_i=1$时$Y^2_i=(Y_{i-1}+1)^2=Y^2_{i-1} + 2Y_{i-1} + 1$,因此$\mathrm{E}(Y_i^2) = p_i[\mathrm{E}(Y^2_{i-1}) + 2\mathrm{E}(Y_{i-1}) + 1]$。
需要注意的是,$\mathrm{E}(Y^2) \neq \mathrm{E}^2(Y)$,不要犯这种低级错误。

代码

// Code by KSkun, 2019/7
#include <cstdio>

const int MAXN = 100005;

int n;
double p[MAXN], e[MAXN], e2[MAXN], dp[MAXN];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%lf", &p[i]);
    }
    for(int i = 1; i <= n; i++) {
        e[i] = (e[i - 1] + 1) * p[i];
        e2[i] = (e2[i - 1] + 2 * e[i - 1] + 1) * p[i];
        dp[i] = dp[i - 1] + (3 * e2[i - 1] + 3 * e[i - 1] + 1) * p[i];
    } 
    printf("%.1lf", dp[n]);
    return 0;
}
[NewGeneration]LQZ的OI复健记录

[NewGeneration]LQZ的OI复健记录

按照AC顺序如下:

1.P1002过河卒

2.P1125笨小猴一遍过

3.P1003铺地毯一遍过

4.P1067多项式输出

5.P1424小鱼的航程(改进版)一遍过

6.P1428小鱼比可爱

7.P2141珠心算测验

8.mengbier

[CF3C]Tic-tac-toe 题解

[CF3C]Tic-tac-toe 题解

题目地址:Codeforces:Problem – 3C – Codeforces、洛谷:CF3C Tic-tac-toe – 洛谷 | 计算机科学教育新生态

题目描述

Certainly, everyone is familiar with tic-tac-toe game. The rules are very simple indeed. Two players take turns marking the cells in a 3 × 3 grid (one player always draws crosses, the other — noughts). The player who succeeds first in placing three of his marks in a horizontal, vertical or diagonal line wins, and the game is finished. The player who draws crosses goes first. If the grid is filled, but neither Xs, nor 0s form the required line, a draw is announced.

You are given a 3 × 3 grid, each grid cell is empty, or occupied by a cross or a nought. You have to find the player (first or second), whose turn is next, or print one of the verdicts below:

  • illegal — if the given board layout can’t appear during a valid game;
  • the first player won — if in the given board layout the first player has just won;
  • the second player won — if in the given board layout the second player has just won;
  • draw — if the given board layout has just let to a draw.

题意简述

给一个井字棋(三子棋)的局面,请判断该局面的状态,状态有以下几种:

  • 下一步X玩家下棋
  • 下一步O玩家下棋
  • 非法状态(正常游戏过程中不会出现的局面)
  • X玩家获胜
  • O玩家获胜
  • 平局

井字棋玩法请百度。

输入输出格式

输入格式:
The input consists of three lines, each of the lines contains characters “.”, “X” or “0” (a period, a capital letter X, or a digit zero).

输出格式:
Print one of the six verdicts: first, second, illegal, the first player won, the second player won or draw.

输入输出样例

输入样例#1:

X0X
.0.
.X.

输出样例#1:

second

题解

大模拟题,细节和分类特别多。分状态讨论符合的情况。

下一步X下棋,仅出现于合法且无人获胜的局面中,特征是局面中X和O的数量相同。
下一步O下棋,仅出现于合法且无人获胜的局面中,特征是局面中X比O的数量多1。
非法状态,有以下几类:X与O的数量的关系既不是相同也不是X比O多1;X获胜之后O仍然下了一步棋(X获胜之后X与O数量相同);O获胜之后X仍然下了一步棋(O获胜之后X比O数量多1)。
X获胜,合法局面中X棋子占据了某一行、列或正副对角线。
O获胜,合法局面中O棋子占据了某一行、列或正副对角线。
平局,合法局面,无人获胜,且棋盘中没有空位。

调试的时候平均一个submission过一个测试点,果然还是我太菜了。

代码

// Code by KSkun, 2019/6
#include <cstdio>

char a[5][5];

int main() {
    scanf("%s%s%s", a[1] + 1, a[2] + 1, a[3] + 1);
    int cntx = 0, cnto = 0;
    bool hasdot = false;
    for(int i = 1; i <= 3; i++) {
        for(int j = 1; j <= 3; j++) {
            if(a[i][j] == 'X') cntx++;
            if(a[i][j] == '0') cnto++;
            if(a[i][j] == '.') hasdot = true;
        }
    }
    if(cntx != cnto && cntx != cnto + 1) {
        puts("illegal"); return 0;
    }
    bool fw = false, sw = false;
    for(int i = 1; i <= 3; i++) {
        if(a[i][1] == a[i][2] && a[i][2] == a[i][3]) {
            if(a[i][1] == 'X') fw = true;
            else if(a[i][1] == '0') sw = true;
        }
    }
    for(int i = 1; i <= 3; i++) {
        if(a[1][i] == a[2][i] && a[2][i] == a[3][i]) {
            if(a[1][i] == 'X') fw = true;
            else if(a[1][i] == '0') sw = true;
        }
    }
    if(a[1][1] == a[2][2] && a[2][2] == a[3][3]) {
        if(a[1][1] == 'X') fw = true;
        else if(a[1][1] == '0') sw = true;
    }
    if(a[1][3] == a[2][2] && a[2][2] == a[3][1]) {
        if(a[1][3] == 'X') fw = true;
        else if(a[1][3] == '0') sw = true;
    }
    if(fw && sw) puts("illegal");
    else if(fw && cntx != cnto + 1) puts("illegal");
    else if(sw && cntx != cnto) puts("illegal");
    else if(fw) puts("the first player won");
    else if(sw) puts("the second player won");
    else if(!hasdot) puts("draw");
    else if(cntx == cnto) puts("first");
    else if(cntx == cnto + 1) puts("second");
    return 0;
}