ARC133E Cyclic Medians
题面传送门
显然如果设\(F_i\)为中位数为\(i\)的方案数,那么最终答案为\(\sum\limits_{i=1}^{V}{F_i\times i}\)
对其差分,设\(H_i\)为中位数至少为\(i\)的方案数,则答案为\(\sum\limits_{i=1}^{V}{H_i}\)
对于判断中位数是否大于等于\(i\),有经典套路:令大于等于\(x\)的数为\(1\),小于等于的为\(0\),转化成对\(01\)数列求答案。
容易发现对于任意\(A\),\(A,1,1\)答案为\(1\),\(A,0,0\)答案为\(0\)。
则可以把序列分为两种:\(n\times m\)对数中有相同与无相同。
若有相同,根据对称性,至少为\(x\)的\(1\)答案等于至少为\(V+1-x\)的\(0\)答案。则算出总方案除以\(2\)即可。
若无相同,则答案就是\(A\),对于\(1\leq i\leq A\)的所有\(H\)均匀贡献。
设\(G=\gcd(n,m)\),则\(x,y\)两个序列\(\bmod G\)分组后,同组相等且\(x,y\)的同组异色。
所以易得答案为\((x^{\frac{n}{G}}(V-x)^{\frac{m}{G}}+(V-x)^{\frac{n}{G}})x^{\frac{m}{G}})^G\)
直接\(O(V(\log n+\log m)+\log mod)\)计算即可。可以做到\(O(V+\log mod+\log n+\log m)\)但没必要。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 200000
#define M 1000000
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*x+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
using namespace std;
I ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
int n,m,A,V,G;ll ToT,Ans;const ll Inv=mpow(2);
I ll calc(int x){return mpow((mpow(x,n/G)*mpow(V-x,m/G)+mpow(V-x,n/G)*mpow(x,m/G))%mod,G);}
int main(){
freopen("1.in","r",stdin);
RI i;scanf("%d%d%d%d",&n,&m,&V,&A);G=__gcd(n,m);ToT=mpow(V,n+m);
for(i=1;i<=A;i++) Ans+=calc(i-1);for(i=1;i<=V+1;i++) Ans+=(ToT-calc(i-1))*Inv%mod;printf("%lld\n",(Ans%mod+mod)%mod);
}