2023.9.27测试

\[\text{省流:1.5h狂砍8分} \]

T1 [ABC311F] Yet Another Grid Task

what??

发现一个点染了黑色后它下面会将一个三角形染成黑色,画个图发现按列考虑比较好

\(f_{i,j}\) 表示第 \(i\) 列最高的黑色格子为第 \(j\) 行的,\(j=n+1\) 表示这一列全是白色。那么有转移

\[f_{i,j}=\sum_{k=j-1}^{n+1}{f_{i-1,k}} \]

可以用后缀和优化做到 \(O(n^2)\)。注意对于一列来说,\(j\) 必须大于等于最高的那个给定的黑色格子,所以 \(f_{i,top_i+1}\sim f_{n+1}=0\)

code
#include<bits/stdc++.h>
using namespace std;

const int N=2010,MOD=998244353;

int n,m,top[N],f[N][N],ans;
char s[N][N];

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
		scanf("%s",s[i]+1);
	
	for(int j=1; j<=m; j++)
	{
		top[j]=n+1;
		for(int i=1; i<=n; i++)
		{
			if(s[i][j]=='#')
			{
				top[j]=i;
				break;
			}
		}
	} 
	
	f[0][n+1]=1;
	for(int i=1; i<=m; i++)
	{
		int tmp=f[i-1][n+1];
		for(int j=n+1; j>=1; j--)
		{
			(tmp+=f[i-1][j-1])%=MOD;
			f[i][j]=tmp;
		}
		for(int j=top[i]+1; j<=n+1; j++)
			f[i][j]=0;
	}
	
	for(int i=1; i<=top[m]; i++)
		(ans+=f[m][i])%=MOD;
	
	printf("%d",ans);

	return 0;
}

T2 子序列

忘记是哪道原题了

T3 字符串

给定一个原串 \(P\),求有多少个串 \(Q\),满足将 \(Q\) 复制一份后,即 \(Q+Q\)\(P\) 的一个子序列。

\(|P|\leq 100\)\(|\sum| \leq 26\)

gj 说这是道典题。考虑枚举断点 \(i\),这时会发现很多合法的 \(Q+Q\) 会在这个断点的左右边出现很多次,这样会重复计算。于是钦定 \(i\) 这一位必须选,设 \(f_{i,j}\) 表示 \(Q_1\)\(i\) 结尾,\(Q_2\)\(j\) 结尾,且 \(i,j\) 都必须选的方案数。

这时我们又发现,对于两个相同但出现位置不一样的子序列,我们很容易重复计算。于是我们用类似最小表示法的思想,要求选出的子序列必须是“最小的”,这样就避免重复计算。

对于每个位置,预处理出在它右边的第一个字符 \(c\) 的位置 \(g_{i,c}\),转移即 \(f_{j,k}\rightarrow f_{g_{c,j},g_{c,k}}\)。对于每个断点 \(i\),答案即 \(\sum\limits_{j=i+1}^nf_{i,j}\)

code
#include<bits/stdc++.h>
using namespace std;

const int N=110,MOD=998244353;

int n,f[N][N],g[N][N],ans;
char s[N];
vector <int> pos[30];

int main()
{
	freopen("str.in","r",stdin);
	freopen("str.out","w",stdout);
	
	scanf("%s",s+1);  n=strlen(s+1);

	for(int i=1; i<=n; i++)
		pos[s[i]-'a'+1].push_back(i);
	for(int i=1; i<=26; i++)
		pos[i].push_back(n+1);
	for(int i=1; i<=26; i++)
		for(int j=0; j<=n; j++)
			g[i][j]=*upper_bound(pos[i].begin(),pos[i].end(),j);

	for(int i=1; i<=n; i++)
	{
		memset(f,0,sizeof(f));
		f[0][i]=1;

		for(int j=0; j<i; j++)
		{
			for(int k=i; k<=n; k++)
			{
				if(!f[j][k])
					continue;
				for(int c=1; c<=26; c++)
					(f[g[c][j]][g[c][k]]+=f[j][k])%=MOD;
			}
		}
		for(int j=i+1; j<=n; j++)
			(ans+=f[i][j])%=MOD;
	}

	printf("%d\n",ans);
	
	return 0;
}
posted @ 2023-09-28 22:13  xishanmeigao  阅读(17)  评论(0)    收藏  举报