我们可以让一个块+2,或让两个相邻的块都+1。
显然,如果初始状态与目标状态的奇偶性相同一定可行。
所以当n*m为奇数,初态奇偶状态是什么都可,(因为末态有奇数有偶数),这个直接快速幂即可
当n*m是偶数时,初始状态必须时偶数,因为末态只有偶数
然后就求出n*m个数,每个数取值L-R,和是偶数的方案:
第一种方法:线性dp+矩阵快速幂加速
dp[i][j]表示选了i个数,和为:偶数/奇数 的方案数,是个1e9的线性dp,用矩阵快速幂加速下即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,-1,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
const int mod= 998244353;
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
int dp[M][2];
struct matrix
{
ll c[2][2];
};
matrix operator *(const matrix &a,const matrix &b)
{
matrix c={0};
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
for(int k=0;k<=1;k++)
c.c[i][j]=(c.c[i][j]+a.c[i][k]*b.c[k][j]%mod)%mod;
return c;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
ll n,m,L,R;
cin>>n>>m>>L>>R;
ll ss=qpow(R-L+1,n*m);
if(n*m%2==1)cout<<ss<<endl;
else
{
ll tp=0;//奇数
if((R-L)&1)tp=(R-L+1)/2;
else
{
if(R&1)tp=(R-L)/2+1;
else tp=(R-L)/2;
}
ll tt=(R-L+1)-tp;//偶数
ll x=n*m;
matrix a={tt,tp,tp,tt};
matrix ans=matrix{1,0,0,1};
while(x)
{
if(x&1)ans=ans*a;
a=a*a;
x/=2;
}
cout<<ans.c[0][0]<<endl;
// dp[0][0]=1;
// for(int i=1;i<=n*m;i++)
// dp[i][0]=dp[i-1][0]*tt%mod+dp[i-1][1]*tp%mod,
// dp[i][1]=dp[i-1][0]*tp%mod+dp[i-1][1]*tt%mod;
// cout<<dp[n*m][0]%mod<<endl;
}
return 0;
}
方法二:线性递推+分析
如果R-L+1是偶数,那么每个数取奇数偶数的可能相同,线性递推发现,奇数偶数的方案一定相同(不懂得可以观察下DP递推的过程)
如果R-L+1是奇数,且R是奇数:
设奇数a个,则偶数a-1个,
第一个数奇数有a种,偶数有b种
到第二个数时:
奇数有:a*b+(a-1)*a=a*a+a*b-a
偶数有:a*a+(a-1)*b=a*a+a*b-b
由于-a+b=-1,所以偶数项偶数比奇数多1
以此类推。
n个数填完,奇数的方案比偶数多1个。只需求出所有奇偶方案数,除以2再加1即可
如果R-L+1是偶数 同理:
设奇数a个,则偶数a+1个,
第一个数奇数有a种,偶数有b种
到第二个数时:
奇数有:a*b+(a+1)*a=a*a+a*b+a
偶数有:a*a+(a+1)*b=a*a+a*b+b
由于a-b=-1,所以偶数项偶数比奇数多1
以此类推。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,-1,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
const int mod= 998244353;
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
ll n,m,L,R;
cin>>n>>m>>L>>R;
ll ss=qpow(R-L+1,n*m);
if(n*m%2==1)cout<<ss<<endl;
else
{
ll x=R-L+1;
ll inv=qpow(2,mod-2),ans;
if(x&1)ans=((ss+1)*((mod+1)/2))%mod;
else ans=((ss)*((mod+1)/2))%mod;
cout<<ans<<endl;
}
return 0;
}