codeforces EC52 div2E. Side Transmutations(組合數學)
阿新 • • 發佈:2018-11-01
題意
給定一個字符集的大小 ,可以從中選取 個字元(可重複)組成一個字串,這裡規定,字串 若經過以下一系列變化所得的字串 ,那麼認為 。
- 選取有效的 ,令 。
- 取字串 的前 個字元組成一個字串 。
- 取字串 的後 個字元組成一個字串
- 將 各自翻轉並交換組成新的字串T。
輸入規定 ,且 可以任選多次。問能組成多少個不同的字串。
題解
對於給定的
,對於這些操作,現把問題轉換一下,實際上就是對
進行操作,每個區間之間都互不相關,可以看成獨立的n個事件組成一個大事件,即對應的乘法原理,n個事件的方案相乘。設每個區間滿足條件的字串個數為
。
為長度為
的字串的對數。分為兩種情況考慮,將左邊的串稱為L,右邊稱為R,設
- 翻轉後 R = L ,那麼只有S種
- 翻轉後 R != L,那麼有 種
總和為
對於每個區間都有
個字串可選 。那麼總的方案數為
程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 2e5+5;
ll pow_mod(ll x, ll n) {
ll res = 1;
while(n) {
if(n&1) res = res*x%mod;
x = x*x%mod;
n >>= 1;
}
return res;
}
ll n,m,A,inv;
ll b[maxn];
ll get(ll i) { // cnt_i
return (pow_mod(A,2*i)+pow_mod(A,i))%mod*inv%mod;
}
int main() {
inv = pow_mod(2,mod-2);
scanf("%lld%lld%lld", &n, &m, &A);
ll mx;
for(int i = 1; i <= m; ++i) {
scanf("%lld", &b[i]);
mx = b[i];
}
for(int i = m; i >= 1; --i)
b[i] = b[i]-b[i-1];
ll AL = pow_mod(A,n-2*mx);
ll ans = 1;
for(int i = 1; i <= m; ++i) {
ans = (ans*get(b[i]))%mod;
}
ans = ans*AL%mod;
printf("%lld\n", ans);
return 0;
}