Loading [MathJax]/extensions/tex2jax.js

Codeforces 1239A:Ivan the Fool and the Probability Theory 题解

主要思路

首先需要知道一个性质:如果第一行和第一列确定,那么这个方案就已经完全确定了。这个可以用归纳法证明:

证明  如果格子\((i – 1, j)\)、\((i, j – 1)\)和\((i – 1, j – 1)\)的颜色确定,那么显然\((i, j)\)的颜色就能被唯一确定。如果第一行和第一列可以被确定,那么根据上述描述,便可生成一个唯一的方案。

所以欲记录方案的个数,那么就要记录合法的第一行和第一列的方案数。这样我们把问题转换到了长条上。

设置\(dp[i][0/1][0/1]\)为到第\(i\)位是否连续、最后一位填的数字。那么转移非常自然,可以自行推导(确实啊)。

最后答案就是把所有情况加起来,再减去非法的两种情况(也就是左上角的三格同色的情况)。

代码

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1239A.cpp
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7, MAX_N = 1e5 + 200;
int n, m, dp[MAX_N][2][2];
int main()
{
scanf("%d%d", &n, &m);
dp[1][1][0] = dp[1][0][0] = 1;
for (int i = 2; i <= max(n, m); i++)
{
// white settings;
// both white;
dp[i][0][1] = dp[i - 1][0][0];
// the prev one is black or double black;
dp[i][0][0] = (1LL * dp[i - 1][1][0] + 1LL * dp[i - 1][1][1]) % mod;
// black settings;
// both black;
dp[i][1][1] = dp[i - 1][1][0];
// double or single;
dp[i][1][0] = (1LL * dp[i - 1][0][0] + 1LL * dp[i - 1][0][1]) % mod;
}
int ans = 0;
for (int i = 0; i <= 1; i++)
for (int j = 0; j <= 1; j++)
ans = (1LL * ans + 1LL * dp[n][i][j] + 1LL * dp[m][i][j]) % mod;
ans -= 2;
while (ans < 0)
ans += mod;
ans %= mod;
printf("%d", ans);
return 0;
}
// CF1239A.cpp #include <bits/stdc++.h> using namespace std; const int mod = 1e9 + 7, MAX_N = 1e5 + 200; int n, m, dp[MAX_N][2][2]; int main() { scanf("%d%d", &n, &m); dp[1][1][0] = dp[1][0][0] = 1; for (int i = 2; i <= max(n, m); i++) { // white settings; // both white; dp[i][0][1] = dp[i - 1][0][0]; // the prev one is black or double black; dp[i][0][0] = (1LL * dp[i - 1][1][0] + 1LL * dp[i - 1][1][1]) % mod; // black settings; // both black; dp[i][1][1] = dp[i - 1][1][0]; // double or single; dp[i][1][0] = (1LL * dp[i - 1][0][0] + 1LL * dp[i - 1][0][1]) % mod; } int ans = 0; for (int i = 0; i <= 1; i++) for (int j = 0; j <= 1; j++) ans = (1LL * ans + 1LL * dp[n][i][j] + 1LL * dp[m][i][j]) % mod; ans -= 2; while (ans < 0) ans += mod; ans %= mod; printf("%d", ans); return 0; }
// CF1239A.cpp
#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9 + 7, MAX_N = 1e5 + 200;

int n, m, dp[MAX_N][2][2];

int main()
{
    scanf("%d%d", &n, &m);
    dp[1][1][0] = dp[1][0][0] = 1;
    for (int i = 2; i <= max(n, m); i++)
    {
        // white settings;
        // both white;
        dp[i][0][1] = dp[i - 1][0][0];
        // the prev one is black or double black;
        dp[i][0][0] = (1LL * dp[i - 1][1][0] + 1LL * dp[i - 1][1][1]) % mod;
        // black settings;
        // both black;
        dp[i][1][1] = dp[i - 1][1][0];
        // double or single;
        dp[i][1][0] = (1LL * dp[i - 1][0][0] + 1LL * dp[i - 1][0][1]) % mod;
    }
    int ans = 0;
    for (int i = 0; i <= 1; i++)
        for (int j = 0; j <= 1; j++)
            ans = (1LL * ans + 1LL * dp[n][i][j] + 1LL * dp[m][i][j]) % mod;
    ans -= 2;
    while (ans < 0)
        ans += mod;
    ans %= mod;
    printf("%d", ans);
    return 0;
}

4 Comments

  1. 我不太懂为什么要减二呢,刚开始
    0 0 1 1
    0 1
    这样,后面还是由这个推出来的,我怎么感觉不仅对答案共享了2

Leave a Reply

Your email address will not be published. Required fields are marked *