Atcoder - abc469 G 题解
题意
给定 \(k\) 个字符串 \(s_i\), 保证其中只有 a 和 b 两种字母。
那么,对于任意一个字符串 \(s_i(i>k)\),满足:\(s_i=s_{i-1}+s_{i-2}+\cdots+s_{i-k}\),其中+表示连接。
现在问你对于一个字符串 \(t\)。要求按照第 \(n\) 个字符串进行如下操作。
- 若 \(s_{n,i}\) 是
a,那么将 \(t\) 的第一个字符移至最后。 - 若 \(s_{n,i}\) 是
b,那么将 \(t\) 翻转。
思路
显然,原题给的两种操作对于后续处理肯定是不优的。考虑将原来的操作转换成等价的操作。
不难发现,再翻转一次之后,原来的a操作从将第一个字符移至最后,变成了从最后一个字符移至第一。
所以我们可以考虑对于一次翻转之后。不急着去将它直接翻转,而是将当前a的操作改成相反的操作(即将第一个字符,一是最后就要变成最后一个字符移至第一,反之同理)。所有的a操作全部结束之后,我再去判断当前b操作的奇偶性判断是否要将整个字符串翻转。
那么难点就在于如何计算究竟作了多少次a操作和b操作。
不难发现,对于b操作,我们只需要关注它的奇偶性即可。
那么我先设一个 \(b\) 数组来代表当前这个字符串中 b 的个数是奇数还是偶数。奇数为1,偶数为0。
那么,通过手玩可以发现。对于 \(b\) 数组它有周期性,其周期长度为 \((k+1)\)。
证明
利用数学归纳法 $$ \because b_1=b_1\mod 2\\ b_2=b_2\mod 2\\ \vdots\\\ b_k=b_k\mod 2\\ b_{k+1}=(b_1+b_2+\cdots+b_k)\mod 2\\ 且 b_{k+1}=(b_2+b_3+\cdots+b_{k}+b_{k+1})\mod 2\\ \therefore b_{k+2}=(b_2+b_3+\cdots+b_k+b_1+b_2+\cdots+b_k)\mod 2\\ \therefore b_{k+1}=(b_1)\mod 2 $$同理得:\(b_{k+3}=b_2\)
故得证
那么我们就可以通过周期性来算出当前是否应该翻转
对于b操作我们就做完了。
对于a操作作不难想到是可以进行矩阵快速幂的。
但是具体应该如何操作,也正是这道题的难点。
首先,我们可以将当前的操作字符串 \(s_n\)。把它对应的之前的所有的字符串中a右移的个数算出来,再对它成一个系数。这个系数就是1和-1的差别。即是否有b去影响a操作。
这里设:\(a_i\) 表示第i个。字符串中要进行操作a多少次。
而对于这个系数。那么会发现它的周期性和数组 \(b\) 是相同的,因为它也是由b操作组成出来的
那么我们定义:\(c_{i,j}=(-1)^{b_{i-1}+b_{i-2}+\cdots+b_{j+1}}\)
显然,这个数组就是我们要求的系数
所以 \(c_{i,j}=c_{i+k+1,j+k+1}\)
那我们也就可以得到必然有一个正整数组成的矩阵 \(A\)。
满足:
也显然这个矩阵 \(A\) 就是将原来 \(a\) 数组按照题目给出的规则进行填充。
而这里我们会注意到它的周期长度为\(2(k+1)\)。你就把这刷出来就可以了
刷完之后进行矩阵快速密再将其乘上对应的系数那么我们需要进行操作a多少次就算出来了。
最后将算出来的进行右移以及翻转即可。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl '\n'
using namespace std;
const int maxn=105;
int mod;
struct mar//矩阵模板
{
int n;
int a[maxn][maxn],c[maxn][maxn];
mar(int _h) : n(_h), a(), c()
{
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
}
void operator*=(const mar &x)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(!a[i][j]) continue;
for(int k=1;k<=n;k++)
{
if(!x.a[j][k]) continue;
c[i][k]=(c[i][k]+a[i][j]*x.a[j][k])%mod;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=c[i][j],c[i][j]=0;
}
};
struct bip//存储答案
{
unsigned u;
bool v;
bip operator*(bip x) const
{
if(!v) return bip{(u+x.u)%mod,x.v};
else return bip{(u+mod-x.u)%mod,!x.v};
}
};
bip a[maxn];
bip cal(int n,int m)//计算
{
for(int i=m;i>=1;i--)
{
if(a[i].u<INT_MAX) a[i].u%=mod;
else a[i].u=(mod-(-a[i].u)%mod)%mod;
a[m+1]=a[m+1]*a[i];
}
mar ans(m+1),sum(m+1);
for(int i=m+2;i<=((m+1)<<1);i++)
{
bool f=0;
for(int j=i-1;j>=i-m;j--)
{
if(j<=m+1)
{
if(f) sum.a[j][i-m-1]=(sum.a[j][i-m-1]+mod-1)%mod;
else sum.a[j][i-m-1]=(sum.a[j][i-m-1]+1)%mod;
if(a[j].v) f=!f;
}
else
{
if(f)
for(int k=1;k<=m+1;k++)
sum.a[k][i-m-1]=(sum.a[k][i-m-1]+mod-sum.a[k][j-m-1])%mod;
else
{
for(int k=1;k<=m+1;k++)
sum.a[k][i-m-1]=(sum.a[k][i-m-1]+sum.a[k][j-m-1])%mod;
}
if(a[j-m-1].v) f=!f;
}
}
}
for(int i=1;i<=m+1;i++) ans.a[i][i]=1;
int p=(n-1)/(m+1);
while(p)
{
if(p&1) ans*=sum;
sum*=sum;
p>>=1;
}
int now=(n-1)%(m+1)+1;
int w=0;
for(int i=1;i<=m+1;i++)
{
if(!ans.a[i][now]||!a[i].u) continue;
w=(w+a[i].u*ans.a[i][now])%mod;
}
return bip{w,a[now].v};
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int m;cin>>m;//原题中的k
for(int i=1;i<=m;i++)
{
string s;cin>>s;
s=' '+s;
for(int j=1;j<s.size();j++)
{
if(s[j]=='a')
{
if(a[i].v) a[i].u--;
else a[i].u++;
}
else a[i].v=!a[i].v;
}
}
int n;cin>>n;
string s,t;cin>>s;
int len=s.size();
mod=len;
bip sum=cal(n,m);
for(int i=0;i<len;i++) t+=s[(i+sum.u)%len];
if(sum.v) reverse(t.begin(),t.end());
cout<<t;
return 0;
}
本文来自博客园,作者:Engle_Chen,欢迎转载,转载请注明原文链接:https://www.cnblogs.com/EagleChenzhilong/p/22205074
,感谢阅读!
浙公网安备 33010602011771号