【JZOJ3159】广告计划

description

如今,在建筑的墙面上或者篱笆桩的表面上涂上一些广告,是一种新的吸引眼球的方法。

现在,小G 运营的一家小公司,决定也试着这样做做广告。小G 在他的篱笆桩上腾出了一些地方供广告使用。每一个篱笆桩都是一个水平的11L 的4 棱柱,其中有一个1L 的面是可以做广告的。1L 的面上划出了L 个1*1 的小正方形(更具体地说是连续L 个水平排列的正方形),每个正方形内写上一个字母。

时间久了,广告做多了难免会出现一些比较麻烦的情况,比如计划改变或者制作出错,因此小G 的仓库里面积累了好多没有用的,上面已经写上L 个字母的篱笆桩。(所有的篱笆桩的大小都是一样的,他们唯一的区别仅仅在于上面写了什么字母)。

小G 决定对于这些篱笆桩进行重新利用,并且有了一些新的想法。

如果将这些篱笆桩竖直的叠放起来,并且依次从左往右,对于每一个篱笆桩顺次从上到下读出上面的字母,那么我们可以得到一些新的比较长的单词,如下图:

这些新的单词能满足小G 的一些新的需要。当然,基于美学考虑,小G 是不允许你删改篱笆桩上已经写上的字母的。

我们更具体地描述这个过程。我们将K 个长度为L 的篱笆桩叠在一起,可以得到一个写有K行L 列共K*L 个字母的面,每一个字母都在对应的唯一的格子里。我们从左上角开始依次向下读出每一个字母可以得到一个字母的序列,比如上图中的这个例子,那么我们读出的结果就是“TOEIIZENITKN”。如果,这个串中有我们所需要的单词,那么显然我们只需要将一些格子刷白,就可以得到我们所需要的了。举个例子,比如小G 想要给圣彼得堡的足球队泽尼特队做个广告,那么很显然只要按照上图中的做法就可以达到小G 想要的效果了。

现在小G已经想好了要做怎样的广告,同时也提供给你了小G仓库中的篱笆桩的类型的描述,你可以认为每一种类型的篱笆桩都是有无数个的。现在小G 想知道至少需要多少个篱笆桩叠起来才可以做出小G 想要的广告。


analysis

  • 什么广义狭义 S A M SAM SAM……暴力

  • f [ i ] [ j ] f[i][j] f[i][j]表示原串匹配到第 i i i位,并且该位在广告墙的第 j j j列中时,可以匹配的任意一个篱笆桩的编号

  • 预处理 f f f就是枚举堆叠 a n s ans ans层、枚举到原串第 i i i位、枚举广告墙第 j j j列,用第 k k k个串来匹配,再一个枚举暴力匹配……

  • 匹配每个串肯定是隔 1 1 1位与原串隔 a n s ans ans位来一一配对的

  • 对于每个 a n s ans ans求出 f f f,从原串的开头枚举,和 a n s ans ans个串再暴力匹配即可

  • 时间跑不满 O ( n 5 ) O(n^5) O(n5),可以过


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 105
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))

using namespace std;

char s[MAXN][MAXN];
ll f[MAXN<<1][MAXN],a[MAXN<<1];
char st[MAXN<<1];
ll n,m,len,ans;
bool bz;

O3 inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
O3 int main()
{
	//freopen("T2.in","r",stdin);
	n=read(),m=read();
	fo(i,1,n)scanf("%s",s[i]+1);
	scanf("%s",st+1),len=strlen(st+1);
	for (ans=1;ans<=len;++ans)
	{
		memset(f,0,sizeof(f));
		fo(i,1,ans)fo(j,1,m)fo(k,1,n)
		{
			ll x=i,y=j;
			for (;x<=len,y<=m;x+=ans,++y)
			{
				if (s[k][y]!=st[x])break;
			}
			if (x>len)
			{
				f[i][j]=k;
				break;
			}
		}
		fo(j,1,m)
		{
			fo(i,1,ans)
			{
				bool flag=1;
				fo(k,1,i)
				{
					if (!f[k][j]){flag=0;break;}
					else a[i-k+1]=f[k][j];
				}
				if (!flag)break;
				fo(k,i+1,ans)
				{
					if (!f[k][j+1]){flag=0;break;}
					else a[ans-k+i+1]=f[k][j+1];
				}
				if (flag){bz=1;break;}
			}
			if (bz)break;
		}
		if (bz)break;
	}
	if (!bz)printf("-1\n");
	else
	{
		printf("%lld\n",ans);
		fd(i,ans,1)printf("%lld ",a[i]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值