ABC469G K-nacci Operations
问题
给定 K 个由 a,b 构成的字符串。对于 i>K,定义 Si=Si−1Si−2…Si−K。按照 SN 的字符依次操作字符串 T:遇到 a 将首字符移到末尾,遇到 b 将整个字符串翻转。求最终的 T。
数据规模:2≤K≤100,N≤1018,初始字符串总长与 ∣T∣ 均不超过 2×105。
写完前面 6 题,到这里我还有 1h,我寻思这把 ABC 总有机会能 AK 了吧,区区 G,我来会会你(划掉)。
注意到 N=1e18,结合这个形似斐波那契数列的 S,大胆猜测思考方向是矩阵快速幂,那就是线性代数的角度了。
显然不可能真正构造 SN,所以先考虑一段操作真正对 T 做了什么。发现两种操作其实都只是在改变原字符串中每个字符最终所在的位置。设 L=∣T∣,记录原位置 p 最后移动到哪里:
ab:p↦p−1,:p↦−p−1,(modL)
于是任意操作串都可以表示成仿射变换:F(p)=kp+b(modL),其中 k∈{−1,1}。也就是说,无论 Si 有多长,我们都只需要记录两个数 (ki,bi),表示整个 Si 对位置产生的变换。
其中 a=(1,−1),b=(−1,−1)。
定义 Fx∗Fy 表示先执行 Fx,再执行 Fy,那么两个变换的复合满足:(kx,bx)∗(ky,by)=(kxky, kybx+by)。
因此对于输入给出的前 K 个字符串,可以直接扫描每个字符,将一整个字符串压成一个仿射变换,复杂度为 O(∑∣Si∣)。
对于 i>K,有 Fi=Fi−1∗Fi−2∗⋯∗Fi−K,不过这个乘法不满足交换律,所以我们需要化简这一长串复合。
令 P=K+1,以及 G=Fi−2∗Fi−3∗⋯∗Fi−K,
那么 Fi=Fi−1∗G,且 Fi−1=G∗Fi−P。
于是 G=Fi−1∗Fi−P−1,代回可以得到 Fi=Fi−12∗Fi−P−1。
注意这里复合不满足交换律,乘法顺序不能改变。
接着计算仿射变换的逆元与平方。由于 k∈{−1,1},所以 k−1=k,从而:(k,b)−1=(k,−kb),并且 (k,b)2=(1,(k+1)b)。
代入前面的递推式:Fi=(1, (ki−1+1)bi−1)∗(ki−P,−ki−Pbi−P)。
分别可以得到 ki=ki−P,以及 bi=ki((ki−1+1)bi−1−bi−P)(modL)。
前者说明 ki 以 P=K+1 为周期,因此 bi 递推中的两个系数:−ki,ki(ki−1+1) 也都以 P 为周期。
至此终于可以开始构造矩阵了。由于新的递推从 i=P+1 开始,定义状态:
VP=b1b2⋮bP
从 Vi−1 转移到 Vi 时,前 P−1 项直接向前移动一位,最后一项根据 bi=−kibi−P+ki(ki−1+1)bi−1 得到。
因此单步转移矩阵为:
Mi=00⋮0−ki10000100⋯⋯⋱⋯⋯00⋮1ki(ki−1+1)
由于转移矩阵以 P 为周期,可以先求出完整一个周期的转移矩阵,然后对周期数量做矩阵快速幂,最后再单独处理剩余的几步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
| struct Matrix {
ll m[maxn][maxn]; int sz; Matrix( int _sz = 0 ) : sz( _sz ) { memset( m, 0, sizeof( m ) ); } void init( ) { for( int i = 1; i <= sz; ++ i ) m[i][i] = 1; } friend Matrix operator * ( const Matrix &a, const Matrix &b ) { Matrix res( a.sz ); for ( int i = 1; i <= res.sz; i++ ) { for( int K = 1; K <= res.sz; ++ K ) { if( a.m[i][K] == 0 ) continue; for( int j = 1; j <= res.sz; ++ j ) res.m[i][j] = ( res.m[i][j] + a.m[i][K] * b.m[K][j] ) % mod; } } return res; }
} A;
Matrix mqpow( Matrix a, ll K ) { Matrix res( a.sz ); res.init( ); for( ; K; K >>= 1, a = a * a ) if( K & 1 ) res = res * a; return res; }
struct F {
ll k, b; F( ll _k = 1, ll _b = 0 ) : k( _k ), b( _b ) { }; friend F operator * ( F x, F y ) { F res; res.k = y.k * x.k; res.b = norm( 1ll * y.k * x.b + y.b ); return res; } ll apply( ll p ) { return norm( 1ll * k * p + b ); }
};
int P, K; ll n;
F f[maxn]; string s[maxn]; string T;
ll getk( ll i ) { int pos = ( i - 1 ) % P + 1; return f[pos].k; }
Matrix getM( ll i ) { Matrix res( P ); for( int j = 1; j < P; ++ j ) { res.m[j][j+1] = 1 % mod; } ll k = getk( i ); ll k1 = getk( i - 1 ); res.m[P][1] = norm( -1ll * k ); res.m[P][P] = norm( 1ll * k * ( k1 + 1 ) ); return res; }
F calc( string s ) { F res = F( 1, 0 ); for( char ch : s ) { F cur; if( ch == 'a' ) cur = F( 1, norm( -1ll ) ); else cur = F( -1, norm( -1ll ) ); res = res * cur; } return res; }
void solve( ) { K = read( ); P = K + 1; for( int i = 1; i <= K; ++ i ) cin >> s[i]; n = read( ); cin >> T; mod = T.size( );
for( int i = 1; i <= K; ++ i ) { f[i] = calc( s[i] ); }
f[P] = {1, 0}; for( int i = K; i >= 1; -- i ) { f[P] = f[P] * f[i]; } ll ansk, ansb;
if( n <= P ) { ansk = f[n].k; ansb = f[n].b; } else { Matrix circle( P ); circle.init( );
for( int i = P + 1; i <= 2 * P; ++ i ) { circle = getM( i ) * circle; }
ll step = n - P; ll cnt = step / P; ll rem = step % P;
Matrix trans = mqpow( circle, cnt );
for( int i = P + 1; i <= P + rem; ++ i ) { trans = getM( i ) * trans; }
ansb = 0; for( int j = 1; j <= P; ++ j ) { ansb = ( ansb + trans.m[P][j] * f[j].b ) % mod; } ansk = getk( n ); }
F anst( ansk, ansb );
string ans = T;
for( int pos = 0; pos < mod; ++ pos ) { ans[anst.apply( pos )] = T[pos]; } cout << ans << '\n'; }
|
矩阵规模为 K+1≤101,总复杂度为 O(∑i=1K∣Si∣+K3logN+∣T∣) 空间复杂度为 O(K2+∣T∣)。
赛后了解到,这些由旋转和翻转组成的仿射变换在复合下构成二面体群;不过本题并不需要预先掌握群论,只需要用到复合封闭和逆元。
记录
- 来源:ABC469 A~G;
- 归属:线性代数 - 矩阵快速幂相关;
- 新增:把巨大操作串压成位置上的仿射变换,利用复合与逆元把 K 项非交换递推化为周期系数的低维线性递推,再按周期做矩阵快速幂;赛时完成主要推导但未调通,当前实现为赛后闭环。
- 分类:待定