题解:AT_agc055_d [AGC055D] ABC Ultimatum
0.前言
省流:275307894a 对 蒟蒻们 使用了 模拟赛
蒟蒻们 rp++
1.思路
是双倍经验的部分分,我的题解。
由于串固定,所以可以先枚举 ABC,BCA,CAB 的数量。
容易想到枚举每个 A,B,C 的位置
显然,第一个字符要作为一个字符串的第一个字符,最后一个字符要作为一个字符串的最后一个字符
故考虑贪心
令 ABC 的数量=\(A\),BCA 的数量=\(B\),CAB 的数量=\(C\),则方案如下
| 串 | ABC | BCA | CAB |
|---|---|---|---|
| 第一个字符所在位置 | \((1,A)\) | \((1,B)\) | \((1,C)\) |
| 第二个字符所在位置 | \((B+1,B+A)\) | \((C+1,C+B)\) | \((A+1,A+C)\) |
| 第三个字符所在位置 | \((C+B+1,C+B+A)\) | \((A+C+1,A+C+B)\) | \((B+A+1,B+A+C)\) |
这里的位置指的是相对位置。
形式化地,如设所有 A 中的第 \(i\) 个 A 为 \(a_i\),则 \((1,A)\) 指 ABC 的 A 应出现在 \((a_1,a_A)\) 范围内。
也即,当每个串最前面的字符出现在每种字符的最前面,最后的字符出现在每种字符的最后面时,若不存在方案,则说明 \(A,B,C\) 不是一个可行的方案。
省流:前面在前面,后面在后面,如果没方案,肯定没方案
具体证明:
点击查看
反证,假设存在一种方案在 \(A,B,C\) 的约束下成立,但在以上方案不成立,则可以通过数次交换 ABC,BCA,CAB 中的 A,B,C,使其最终化为此方案
如我手搓的样例
ABCCAB
如选取 \(a_1,b_1,c_1\) 组成 ABC,\(c_2,a_2,b_2\) 组成 CAB,
则显然 \(a_1,b_1,c_2\) 组成 ABC,\(c_1,a_2,b_2\) 组成 CAB 一定也是一个可行的方案。
故,在以上方案成立是当前方案成立的充分必要条件。
省流:上一句话是对的
于是,你就得到了一种在 \(O(n^3)\) 时间内求出一个方案是否成立的方法
接下来,考虑优化枚举过程。
考虑给定\(A\), \(B\) 如何计数,则上面的最优分配方案可以转化为对于\(p_a,i\) 和 \(p_b,B+i\) 等的顺序限制。
然后设 \(f_{a,b,c}\) 表示当前填了前 \(a\) 个 A,\(b\) 个 B,\(c\) 个 C 的方案数。这个dp是 \(O(n^3)\) 的。
对于一般的情况,只需要枚举哪些子集对是合法的,容斥即可计算答案。
注意到如果两个子集 \(max\) 加起来大于 \(n\) 肯定是无解的,因此只有
\(O(2^nn)\) 个子集对需要计算,时间复杂度 \(O(2^nn^4)\),可以通过。
2.代码
是从双倍经验的代码改过来的,故有点丑。
#include <bits/stdc++.h>
using namespace std;
const int N=20,mod=998244353;
using ui=unsigned;
int n;
ui ans,dp[N][N][N][4];
char a[N*3],s1[N]="11111111111111111",s2[N]="11111111111111111";
int main() {
scanf("%d%s",&n,a+1);
ans=0;
for(int x=0; x<=n; ++x) {
for(int z=0; z<=n; ++z) {
int Z=z;
while(Z<=n&&s1[Z]=='0')Z++;
int X=x;
while(X<=n&&s2[X]=='0')X++;
int y=n-X-Z;
if(y<0)continue;
dp[0][0][0][0]=1;
for(int i=0,t; i<=n; ++i) {
for(int j=0; j<=n && j<=i+x; ++j) {
for(int k=max(i-z,0); k<=n && k<=j+y; ++k) {
t=i+j+k;
if(!t)continue;
memset(dp[i][j][k],0,sizeof(dp[i][j][k]));
if(i && j-i<x && (a[t]=='A' || a[t]=='?')) {
dp[i][j][k][0]+=dp[i-1][j][k][0];
dp[i][j][k][1]+=dp[i-1][j][k][1];
dp[i][j][k][2]+=dp[i-1][j][k][2];
dp[i][j][k][3]+=dp[i-1][j][k][3];
}
if(j && k-j<y && (a[t]=='B' || a[t]=='?')) {
dp[i][j][k][0]+=dp[i][j-1][k][0];
dp[i][j][k][1]+=dp[i][j-1][k][1];
dp[i][j][k][2]+=dp[i][j-1][k][2];
dp[i][j][k][3]+=dp[i][j-1][k][3];
}
if(k && i-k<z && (a[t]=='C' || a[t]=='?')) {
dp[i][j][k][0]+=dp[i][j][k-1][0];
dp[i][j][k][1]+=dp[i][j][k-1][1];
dp[i][j][k][2]+=dp[i][j][k-1][2];
dp[i][j][k][3]+=dp[i][j][k-1][3];
}
if(j-i==x) {
dp[i][j][k][1]+=dp[i][j][k][0];
dp[i][j][k][3]+=dp[i][j][k][2];
dp[i][j][k][0]=dp[i][j][k][2]=0;
}
if(i-k==z) {
dp[i][j][k][2]+=dp[i][j][k][0];
dp[i][j][k][3]+=dp[i][j][k][1];
dp[i][j][k][0]=dp[i][j][k][1]=0;
}
// cerr<<dp[i][j][k][0]<<' '<<dp[i][j][k][1]<<' '<<dp[i][j][k][2]<<' '<<dp[i][j][k][3]<<'\n';
}
}
}
ans+=dp[n][n][n][3];
ans%=mod;
}
}
printf("%u\n",ans);
return 0;
}
3.后记
- 膜拜巨佬 275307894a
- 双倍经验,而且呈包含关系
给好不容易搞懂此题的本蒟蒻一个赞吧

浙公网安备 33010602011771号