1. 程式人生 > 實用技巧 >Codeforces Round #594 (Div. 2) C. Ivan the Fool and the Probability Theory (思維,遞推)

Codeforces Round #594 (Div. 2) C. Ivan the Fool and the Probability Theory (思維,遞推)

  • 題意:給你一個\(n\)x\(m\)的矩陣,需要在這些矩陣中塗色,每個格子可以塗成黑色或者白色,一個格子四周最多隻能有\(2\)個和它顏色相同的,問最多有多少種塗色方案.

  • 題解:首先我們考慮一維的情況,一個格子的方案數是\(2\),兩個格子的方案數是\(4\),我們記\(f[1]=2\),\(f[2]=4\),然後我們考慮三個格子的情況,假如我們最後兩個格子塗成一樣的顏色,那麼情況數就是\(f[1]\),若最後兩個兩個格子的顏色不一樣,那麼我們可以看成在\(f[2]\)的基礎上塗第三個格子,這樣塗的話是固定的,即方案數為\(f[2]\),所以可以推出\(f[3]=f[1]+f[2]\)

    ,進而求出遞推式:\(f[i]=f[i-1]+f[i-2]\).

    我們可以先看第一行的情況,不難發現,假如這一行出現兩個連續的顏色時,整個圖就確定了,而且這種情況下的第一列一定是黑白相間的,假如沒有出現兩個連續的顏色,即\(oxoxoxox\)\(xoxoxoxo\)這兩個特殊情況,我們是不能確定下面行的情況的,這時我們就可以將這兩個情況單獨拿出來,去看第一列的情況,在計算這一列的時候,我們必須要保持第一行是\(oxoxoxoxo\)\(xoxoxoxoxo\),就像之前說的,假如出現兩個連續的顏色時,第一行的顏色一定是黑白相間的,但是當第一列出現\(oxoxoxox\)\(xoxoxoxo\)

    這樣的情況時,第一行並不一定是黑白相間的,而不是黑白相間的情況我們在\(f[n]\)中已經計算過了,所以方案數為\(f[m]-2\),所以答案就是\(f[n]+f[m]-2\).

  • 程式碼:

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
 
int n,m;
ll f[N];
 
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	f[1]=2,f[2]=4;
 
	cin>>n>>m;
 
	rep(i,3,max(n,m)) f[i]=f[i-1]%mod+f[i-2]%mod;
 
	cout<<(f[n]+f[m]-2)%mod<<'\n';
 
    return 0;
}