可以将左半部分区间划分为[1,b1],[b1+1,b2],[b2+1,b3]...若干个小段,每一段都可以和右半部分对称位置上的做交换。
根据Burnside引理,等价类的个数等于所有置换不动点个数的平均值。又根据Polya定理,置换f不动点的个数等于$A^{m(f)}$,A为颜色数,m(f)为f的循环节个数
假如一段长度为k区间可以和对面互换,那么该置换的循环节个数为n-k(左右两边对称的k个必须涂成一样颜色,其余的n-2k个任意涂色),不动点个数即为$A^{n-k}$
对b数组从小到大排序,设c[i]=b[i]-b[i-1],由于若干个小段可以拼成一个长度为这些小段之和的大段,最终结果为$frac{A^{n}+A^{n-c[1]}+A^{n-c[2]}+A^{n-(c[1]+c[2])}+...}{2^m}$,写成乘积的形式即为$frac{A^n(1+A^{-c[1]})(1+A^{-c[2]})...}{2^m}$,可以在$O(m(logm+logn))$的时间内求出
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=2e5+10,mod=998244353,inf=0x3f3f3f3f; 5 int n,m,A,b[N]; 6 int Pow(int x,int p) { 7 int ret=1; 8 for(; p; p>>=1,x=(ll)x*x%mod)if(p&1)ret=(ll)ret*x%mod; 9 return ret; 10 } 11 int main() { 12 scanf("%d%d%d",&n,&m,&A); 13 for(int i=0; i<m; ++i)scanf("%d",&b[i]); 14 sort(b,b+m); 15 for(int i=m; i>0; --i)b[i]-=b[i-1]; 16 int ans=1; 17 for(int i=0; i<m; ++i)ans=(ll)ans*(1+Pow(A,mod-1-b[i]))%mod; 18 ans=(ll)ans*Pow(A,n)%mod*Pow(2,mod-1-m)%mod; 19 printf("%d ",ans); 20 return 0; 21 }