1. 程式人生 > 其它 >E. Height All the Same——Codeforces Round #630 (Div. 2)

E. Height All the Same——Codeforces Round #630 (Div. 2)

E. Height All the Same

題目大意

給出\(n * m\)的方格,每個方格上面可以放置立方體,初始時座標為\((i,j)\)的方格上有\(a_{i,j}\)個立方體,現在有兩個操作:

  • 選擇相鄰的兩個方格並在每個方格上面放置一個立方體
  • 選擇一個人方格並在這個方格上放置兩個立方體

要求在有限次操作內使得每個方格上的立方體數量相等。
現在給出\(a_{i,j}\)的取值\([L,R]\),問你有多少種初始數量的方案可以滿足上述要求。

解題思路

因為操作可以任意次,所以不需要考慮具體操作次數,並且可以發現我們可以通過操作\(1\)做到選擇任意兩個方格進行加\(1\)的操作。
然後就是想到因為最後數量需要一樣,每次都是加\(1\)

或者加\(2\),所以考慮初始狀態的奇偶性。假設全是奇數或者全是偶數,則可以通過操作\(2\)完成目標。
假設初始時有\(x\)個奇數,\(y\)個偶數。
因為操作\(2\)不會改變整體方格上立方體數量的奇偶性,只有在奇偶性相同的方格上進行操作\(1\),才會改變整體的奇偶性,如:選擇兩個奇數數量的方格進行操作1,則整體奇數數量會減\(2\),偶數數量會加\(2\),而選擇奇偶性不同的方格操作相當於沒變(奇偶性不發生該改變)。
並且每次更改都是\(2\),所以初始奇數的數量或者偶數的數量一定要有一個是偶數,這樣才可以滿足要求。

  • 如果\(n * m\)是奇數,那麼奇數和偶數中一定有一個的數量是偶數,答案直接就是 \((R - L + 1)^{n * m}\)
  • 如果是偶數,則需要計算,利用組合數學得出\(\sum_{i = 0}^{n * m} C_{n * m}^i * x^i * y^{(n * m - i)} * [i \% 2 = 0]\)

對於第二種情況,
根據二項式定理可得:\((x - y) ^{(n * m)} = \sum_{i = 0}^{n * m} C_{n * m}^{i} x^i * y^{(n *m - i)} * (-1)^{n * m - i} = \sum_{i = 0}^{n * m} C_{n * m}^{i} x^i * y^{(n *m - i)} * (-1)^{i}\)
所以奇數項是\(-1\),偶數項是\(1\)

,我們只要求出偶數項的值即可。
\((x + y)^{n*m} = \sum_{i = 0}^{n * m} C_{n * m}^{i} x^i * y^{(n *m - i)}\)
因此\(ans = \cfrac{(x-y)^{n * m} + (x + y^{n * m})}{2}\)

故:
\(n *m\)是奇數時,\(ans = (R - L + 1)^{n * m}\)
否則\(ans = \cfrac{(x-y)^{n * m} + (x + y^{n * m})}{2}\ \ (x為奇數出現的數量,y為偶數出現的數量)\)

Code

#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
#define V vector
using namespace std;
const int N = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;

inline char nc() {
    static char buf[1000000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
template <typename _Tp> inline void read(_Tp&sum) {
    char ch = nc(); sum = 0;
    while (!(ch >= '0'&&ch <= '9')) ch = nc();
    while (ch >= '0'&&ch <= '9') sum = (sum << 3) + (sum << 1) + (ch - 48), ch = nc();
}

ll n,m,l,r;

ll ksm(ll x,ll y)
{
    ll p = 1;
    while(y)
    {
        if(y & 1)p = p * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return p;
}

void solve(){
    read(n);
    read(m);
    read(l);
    read(r);
    if((n * m) & 1){
        printf("%lld\n",ksm((r - l + 1), n * m));
    }else{
        ll x = 0, y = 0;
        if((l & 1) && (r & 1)){
            x = (r - l) / 2;
            y = (r - l) / 2 + 1;
        }else if(!(l & 1) && !(r & 1)){
            x = (r - l) / 2 + 1;
            y = (r - l) / 2;
        }else{
            x = y = (r - l + 1) / 2;
        }
        printf("%lld\n",((ksm(abs(x - y), n * m) + ksm(x + y, n * m)) % mod) * ksm(2ll, mod - 2) % mod);
    }
}

int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif

    int T = 1;
    // scanf("%d",&T);
    while(T--){
        solve();
    }
    return 0;
}
Code will change the world !