E1:设dp[i][j],表示在第i个位置的当前新状态超过原状态j分的方案数是dp[i][j],那么对于这种情况直接进行转移即可,如果a[i]==b[i]显然k种选择都可以,不影响j,如果不一样,这个位置填了a[i]那么状态从dp[i-1][j+1]转移过来,如果填了b[i]就是dp[i-1][j-1]转移,当然也可以两个都不填,那么剩下一共是k-2种选择,j不变,最后答案将所有超过分数为正数的加起来即可,因此总体复杂度O(nk)。
E2:我们可以从E1的递推式子中发现,新状态超过原状态的方案和原状态超过新状态的方案这两者是等价的问题,那么我们可以进行简单使用总方案数减去分数相同的方案数最后除二就是答案,那么我们可以枚举新状态一共多原状态j分,原状态一共多新状态j分,因为这两者在最后是打平的,这两者在只有在a[i]!=b[i]的时候才会发生超对方一分的情况,那么我们记num为一共有多少个a[i]!=b[i]的情况,然后我们枚举共超过对方i分,那么我们需要从num中挑i次是选择的a,再从剩下的num-i次中选择b,那么还剩下nun-2*i的部分是a[i]!=b[i],但是又不能影响超过的分数,那么只能选既不是a[i]也不是b[i]共k-2中选择,那么乘上(k-2)(num-2*i),最后n-num的部分是a[i]==b[i],对于这部分不论取什么对于两者的贡献是一样的,那么一共有k种选择,所以最后再乘上k(n-num)即可。
O(nk)
// ——By DD_BOND #include<bits/stdc++.h> using namespace std; typedef long long ll; const int MOD=998244353; ll dp[2020][4100]; int a[2020],b[2020]; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); ll n,k; cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) b[i]=a[i%n+1]; dp[0][n+1]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=2*n+1;j++){ if(a[i]==b[i]) dp[i][j]=dp[i-1][j]*k%MOD; else dp[i][j]=((dp[i-1][j-1]+dp[i-1][j+1])%MOD+dp[i-1][j]*(k-2)%MOD)%MOD; } } ll ans=0; for(int i=n+2;i<=2*n+1;i++) ans=(ans+dp[n][i])%MOD; cout<<ans<<endl; return 0; }
O(nlogk)
1 // ——By DD_BOND 2 3 #include<bits/stdc++.h> 4 5 using namespace std; 6 7 typedef long long ll; 8 9 const int MOD=998244353; 10 const int MAXN=1e6+10; 11 12 ll qpow(ll a,ll n){ll sum=1;while(n){if(n&1)sum=sum*a%MOD;a=a*a%MOD;n>>=1;}return sum;} 13 14 int a[MAXN],b[MAXN]; 15 int fac[MAXN],rfac[MAXN],inv[MAXN]; 16 17 int C(int n,int m){ 18 if(n-m<m) m=n-m; 19 if(m==0) return 1; 20 return 1ll*fac[n]*rfac[m]%MOD*rfac[n-m]%MOD; 21 } 22 23 int main(void) 24 { 25 ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 26 fac[1]=rfac[1]=inv[1]=1; 27 for(int i=2;i<MAXN;i++) inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD; 28 for(int i=2;i<MAXN;i++) fac[i]=1ll*fac[i-1]*i%MOD,rfac[i]=1ll*rfac[i-1]*inv[i]%MOD; 29 int n,k,num=0,ans=0; cin>>n>>k; 30 for(int i=1;i<=n;i++) cin>>a[i]; 31 if(k==1) return cout<<0<<endl,0; 32 for(int i=1;i<=n;i++) 33 if(a[i]!=a[i%n+1]) 34 num++; 35 for(int i=0;2*i<=num;i++) ans=(ans+1ll*C(num,i)*C(num-i,i)%MOD*qpow(k-2,num-2*i)%MOD*qpow(k,n-num)%MOD)%MOD; 36 cout<<(qpow(k,n)-ans+MOD)%MOD*inv[2]%MOD<<endl; 37 return 0; 38 }