专栏文章
P8194
P8194题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mingb4el
- 此快照首次捕获于
- 2025/12/02 01:56 3 个月前
- 此快照最后确认于
- 2025/12/02 01:56 3 个月前
爆标做法。考虑把 DP 套 DP 直接扔掉,钦定当前状态按后 个分段,强行分讨去掉重复情况:
最后一个分段,;
若 相邻,最后两个分段,要求这两个交换,否则被两个 段替代,。
若 是正方形,最后四个分段,先让 ,然后扣掉可以被替代的方案。
被 分一段的某个方案替代:
若 顺序是 ,被四个 段替代,。
若 顺序是 ,这三种情况只可能被 分段的情况替代,若 是正方形则 。
若 顺序是 ,若 相邻,此时可以钦定为按 分段。若 分段,能被 替代。若按 分段,能被 替代;若按 分段,在 中必有两个相邻,可以 分段。因此可以转移 ,否则若 是正方形就转移 。
若 顺序是 ,若 相邻,钦定 分段, 分段的情况一定有 相邻,总是可以分成两段 ,因此已经被包含,转移 。否则情况比较复杂:
如果能分段 ,就是 。另一种方案是分段 且 的顺序是 ( 必须交换,否则被 分段的情况覆盖)。我们已知 在交错的位置,因此 必须能成段。注意,此时我们的前提条件是扣除 成段的方案数。
现在我们考虑 成段时 要成段,考虑 是否交换。若不交换,那这两个成段的限制已经满足,为 。否则限制变为 要能成段且 必须交换。发现这变成了一个子问题,我们可以拿一个 算出,为 。转移就是 。
若 不能分段,就只有分段 ,比上面多一种 不交换的情况 。转移是 。
若被 分一段的某个方案替代(首先要求 相邻):
不能留在原位,否则被上一种情况统计,因此只有 型。
对 型,可以钦定为按 分段。这要求 是断点,和上面的讨论类似,若按 分段能拆成 ,若按 分段能将 拆成 。转移 。
对 型,因为 也相邻,就能被 替代(同上, 分段的情况被包含)。转移 。
综上,我们做到了小常数 。
CPP#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int t,n,f[100005],g[100005];
char s[100005];
bool check2(int x){
return x>=2&&(abs(s[x]-s[x-1])==3||(abs(s[x]-s[x-1])==1&&(s[x]+s[x-1])%3!=1));
}
bool check4(int x){
if(x<4)return 0;
int t=0;
for(int i=0;i<4;i++)t|=1<<(s[x-i]-'0');
return t==54||t==108||t==432||t==864;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),f[0]=1,cin>>t;
while(t--){
cin>>s+1,n=strlen(s+1);
for(int i=1;i<=n;i++){
g[i]=check4(i)?(g[i-2]+f[i-4])%mod:0,f[i]=f[i-1];
if(check2(i))f[i]=(f[i]+f[i-2])%mod;
if(check4(i)){
f[i]=(f[i]+23ll*f[i-4])%mod;
if(check4(i-1))f[i]=((f[i]-3ll*f[i-5])%mod+mod)%mod;
if(check2(i-1))f[i]=(f[i]-f[i-4]+mod)%mod;
else if(check4(i-1))f[i]=(f[i]-f[i-5]+mod)%mod;
if(check2(i-2))f[i]=(f[i]-f[i-4]+mod)%mod;
else{
if(check4(i-1)){
f[i]=(f[i]-f[i-5]+mod)%mod;
if(check4(i-2))f[i]=(f[i]-g[i-4]+mod)%mod;
}
else f[i]=(f[i]-g[i-2]+mod)%mod;
}
if(check2(i))f[i]=(f[i]-2ll*f[i-4]%mod+2*mod)%mod;
}
}
cout<<f[n]<<'\n';
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...