CF 1065 E. Side Transmutations

E. Side Transmutations

http://codeforces.com/contest/1065/problem/E

题意:

  长度为n的字符串,字符集为A,问多少不同的字符串。两个字符串相同:

  1. 在给定的数组b中,找到一个数b[i],设k=b[i]
  2. 将1~k,与n-k+1~n 的字符串翻转,然后交换位置。新形成的字符串与原来的字符串相等。

分析:

  考虑只有一个b[i]的影响,那么对于一个字符串,分成了三段,前面k个,后面k个,中间的。中间的部分就是$A^{n-k-k}$,再看两边形成多少种字符串,使得这些都是不同的。

  如果存在一个字符串a,经过变换后成了b,那么说明a=b,我们只要求出有多少个这样的相等对数,用总的减去这些,就是所有不同的。(相当于存在一个a=b,就是减少了一个的字符串,因为两个相同了,只计算一次。像并查集维护联通块一样,存在一条边,联通快的个数就减少一个)

  那么总的就是$A^{k}\timesA^{k} = A^{k+k}$,前面k个和后面k个的总方案数。然后如果

  那么所有的字符串为2

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define fi(s) freopen(s,"r",stdin);
12 #define fo(s) freopen(s,"w",stdout);
13 using namespace std;
14 typedef long long LL;
15 
16 inline int read() {
17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
19 }
20 
21 const int N = 200005;
22 const LL mod = 998244353;
23 
24 LL ksm(LL a, LL b) {
25     LL res = 1;
26     while (b) {
27         if (b & 1) res = res * a % mod;
28         a = a * a % mod;
29         b >>= 1;
30     }
31     return res;
32 }
33 
34 LL b[N];
35 
36 int main() {
37     int n = read(), m = read();
38     LL A = read();
39     for (int i=1; i<=m; ++i) b[i] = read();
40     LL ans = 1, inv2 = ksm(2, mod - 2);
41     for (int i=1; i<=m; ++i) {
42         LL L = b[i] - b[i - 1];
43         LL tmp = ksm(A, L);
44         ans = ans * tmp % mod * (tmp + 1) % mod;
45         ans = ans * inv2 % mod;
46     }
47     ans = ans * ksm(A, n - b[m] - b[m]) % mod;
48     cout << ans;
49     return 0;
50 }

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/9784410.html