[Codeforces Round #630 (Div. 2)] - E. Height All the Same (組合數學)
E. Height All the Same
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
Alice has got addicted to a game called Sirtet recently.
In Sirtet, player is given an n×mn×m grid. Initially ai,jai,j cubes are stacked up in the cell (i,j)(i,j). Two cells are called adjacent if they share a side. Player can perform the following operations:
- stack up one cube in two adjacent cells;
- stack up two cubes in one cell.
Cubes mentioned above are identical in height.
Here is an illustration of the game. States on the right are obtained by performing one of the above operations on the state on the left, and grey cubes are added due to the operation.
Player's goal is to make the height of all cells the same (i.e. so that each cell has the same number of cubes in it) using above operations.
Alice, however, has found out that on some starting grids she may never reach the goal no matter what strategy she uses. Thus, she is wondering the number of initial grids such that
- L≤ai,j≤RL≤ai,j≤R for all 1≤i≤n1≤i≤n, 1≤j≤m1≤j≤m;
- player can reach the goal using above operations.
Please help Alice with it. Notice that the answer might be large, please output the desired value modulo 998,244,353998,244,353.
Input
The only line contains four integers nn, mm, LL and RR (1≤n,m,L,R≤1091≤n,m,L,R≤109, L≤RL≤R, n⋅m≥2n⋅m≥2).
Output
Output one integer, representing the desired answer modulo 998,244,353998,244,353.
Examples
input
Copy
2 2 1 1
output
Copy
1
input
Copy
1 2 1 2
output
Copy
2
Note
In the first sample, the only initial grid that satisfies the requirements is a1,1=a2,1=a1,2=a2,2=1a1,1=a2,1=a1,2=a2,2=1. Thus the answer should be 11.
In the second sample, initial grids that satisfy the requirements are a1,1=a1,2=1a1,1=a1,2=1 and a1,1=a1,2=2a1,1=a1,2=2. Thus the answer should be 22.
題意:
現在有一個\(n*m\)的方格,第\(\mathit i\)行第\(\mathit j\)列有\(a[i][j]\)個方塊。
你可以執行以下操作任意次:
1、選擇\((i,j)\)使\(a[i][j]\)加上\(\text 2\)。
2、選擇兩個相鄰的方格,將其方格數加上\(\text 1\)。
現在問初始\(a[i][j]\)可以是\([L,R]\)中的任意數,有多少種初始方案可以通過任意次數的操作后使所有的\(a[i][j]\)相等。
思路:
因為操作1不改變奇偶性,而同奇偶性的數一定可以通過操作1變成相等的數,所以對於一個\(n*m\)的方格,只考慮其奇偶性,問題可以轉化為,能否選擇兩個相鄰的方格,使其奇偶性翻轉,最后使整個方格奇偶性一致。
這是一個經典的問題,解法為:奇數和偶數的個數都是奇數是不行的,否則可行。
可以觀看下圖,紅色代表奇數,白色代表偶數。
我們可以通過一次翻轉使其變成:
當將奇數移動到一些特殊的位置后,有因為剩下的偶數的個數\(cnt\)為偶數,可以通過\(cnt/2\)次翻轉操作變為:
全部變成紅色(奇數)。
只要奇數的個數和偶數個數的至少一個為偶數,就可以通過這種方法將其變成同奇偶性。
來思考本題的2種情況:
如果\(n*m\)是奇數,那么奇數的個數和偶數個數的至少一個為偶數,則所有初始狀態都滿足條件。
答案為\((R-L+1)^{n*m}\)。
否則,設\(\mathit x\)為\([L,R]\)中奇數的個數,設\(\mathit y\)為\([L,R]\)中偶數的個數。
\(ans= \sum _{i=0}^{n*m}C^{i}_{n*m}*x^i*y^{n*m-i},i\%2=0\)
那么答案就是\(\sum _{i=0}^{n*m}C^{i}_{n*m}*x^i*y^{n*m-i}\)二項式中偶數項的和。
構造二項式\((x-y)^{n*m}=\sum _{i=0}^{n*m}C^{i}_{n*m}*x^i*y^{n*m-i}*(-1)^{n*m-i},(-1)^{n*m-i}=(-1)^i\)的奇偶項為正負交替的。
則:
\(ans=\frac{(x+y)^{n*m}+(x-y)^{n*m}}{2}\)
代碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
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;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
const ll mod = 998244353;
int main()
{
#if DEBUG_Switch
freopen("C:\\code\\input.txt", "r", stdin);
#endif
//freopen("C:\\code\\output.txt","r",stdin);
ll n, m, l, r;
cin >> n >> m >> l >> r;
ll x = r - l + 1;
if (n * m % 2 == 1)
{
printf("%lld\n", powmod(x, n * m, mod) );
} else
{
ll ans = powmod(x, n * m, mod) + ((x & 1) ? 1 : 0);
ans %= mod;
ans = ans * powmod(2ll, mod - 2ll, mod);
ans %= mod;
printf("%lld\n", ans );
}
return 0;
}