题解 [ARC119F] AtCoder Express 3

传送门

有两种切入思路

pb 思路:
如果方案确定,那么就变成了最短路问题
如果存在一大段相同字符显然可以用另一种字符跳过去
所以猜测每个时刻需要考虑的字符数是较少的,可以建出自动机处理
然后在自动机上跑 DP(DP 套 DP)就行了
自动机可以经过(很)大力手玩建出来

题解思路:
还是最短路,发现只关心最靠右的 A 和 B 在哪
\(f_{i, j, k, 0/1}\) 为到第 \(i\) 个站台,到最靠右 A 最短路为 \(j\),到最靠右 B 最短路为 \(k\),上个位置是 A/B 方案数
这样是 \(O(n^3)\)
然后发现有大量状态是无用的
比如说到最靠右 B 比最靠右 A 远好多,那么到这个 B 是没有用的,不管是去下一个 A 还是下一个 B 都是走 A 更近
所以将定义改为 \(f_{i, j, k, 0/1}\) 为到第 \(i\) 个站台,到最靠右或当前 A 所在的全 A 连续段的最后一个 A 最短路为 \(j\)
到最靠右或当前 B 所在的全 B 连续段的最后一个 B 最短路为 \(k\),第 \(i\) 个位置是 A/B 方案数
可能需要比较细致的读题,比如说读入字符串长度为 \(n-1\) 而不是 \(n\)
复杂度 \(O(n^2)\)

点击查看~~大量借鉴于 std 的~~代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 4010
#define ll long long
//#define int long long

int n, k;
int now;
char s[N];
const ll mod=1e9+7, inv2=(mod+1)>>1;
ll f[2][N][5][2], ans;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}

signed main()
{
	scanf("%d%d%s", &n, &k, s+1);
	if (s[1]!='B') f[now][1][-1][0]=1;
	if (s[1]!='A') f[now][0][1][1]=1;
	for (int i=2; i<n; ++i,now^=1) {
		memset(f[now^1], 0, sizeof(f[now^1]));
		for (int j=0; j<=i; ++j) {
			for (int k=-2; k<=2; ++k) {
				int dis_a=j, dis_b=j+k;
				// if (dis_b<=0) continue;
				if (f[now][j][k][0]) {
					if (s[i]!='B') md(f[now^1][min(dis_a+1, dis_b+2)][dis_b-min(dis_a+1, dis_b+2)][0], f[now][j][k][0]);
					if (s[i]!='A') md(f[now^1][dis_a][min(dis_a+1, dis_b+1)-dis_a][1], f[now][j][k][0]);
				}
				if (f[now][j][k][1]) {
					if (s[i]!='B') md(f[now^1][min(dis_a+1, dis_b+1)][dis_b-min(dis_a+1, dis_b+1)][0], f[now][j][k][1]);
					if (s[i]!='A') md(f[now^1][dis_a][min(dis_a+2, dis_b+1)-dis_a][1], f[now][j][k][1]);
				}
			}
		}
	}
	for (int j=0; j<=n; ++j) {
		for (int k=-2; k<=2; ++k) {
			int dis_a=j, dis_b=j+k;
			if (min(dis_a, dis_b)<::k) {
				md(ans, f[now][j][k][0]), md(ans, f[now][j][k][1]);
				// cout<<"add: "<<dis_a<<' '<<dis_b<<" A ("<<f[now][j][k][0]<<")"<<endl;
				// cout<<"add: "<<dis_a<<' '<<dis_b<<" B ("<<f[now][j][k][1]<<")"<<endl;
			}
			// else {
			// 	cout<<"del: "<<dis_a<<' '<<dis_b<<" A ("<<f[now][j][k][0]<<")"<<endl;
			// 	cout<<"del: "<<dis_a<<' '<<dis_b<<" B ("<<f[now][j][k][1]<<")"<<endl;
			// }
		}
	}
	printf("%lld\n", ans);

	return 0;
}
posted @ 2022-06-22 19:30  Administrator-09  阅读(4)  评论(0编辑  收藏  举报