2017 JUST Programming Contest 2.0 题解

347 阅读2分钟

比赛链接

B

思路

dpidp_i是前ii个元素的方案数。考虑第ii个元素,在它前面的某个元素kk的后面插一个板,在[k+1,i1][k+1,i-1]的元素后面不插板,此时对答案的贡献就是dpkdp_k。这样可以一直插到哪里呢?如果第kk个元素在[k+1,i][k+1,i]中出现过,那就不可能再往前找了,因为kk后面必然要插一个板。
维护以第ii个元素结尾的最长的不含重复元素的连续子序列长度,记为fif_i。根据上文可知,dpi=Σj=if[i]i1dpjdp_i=\Sigma_{j=i-f[i]}^{i-1}dp_j

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const ll N=1E4+10,P=1E9+7;
ll n,Left=1;
ll vis[20],f[N],dp[N];
string s;
void print()
{
	rep(i,1,n)
		cout<<f[i]<<" ";
	cout<<endl;
}
int main()
{
	In(1,&n);
	cin>>s;
	s=' '+s;
	rep(i,1,n)
	{
		while(vis[s[i]-'0'])
		{
			--vis[s[Left]-'0'];
			++Left;
		}
		++vis[s[i]-'0'];
		f[i]=i-Left+1;
	}
	dp[0]=1;
	rep(i,1,n)
		rep(j,1,f[i])
			dp[i]=(dp[i]+dp[i-j])%P;
	Out(1,dp[n]);
}

J

思路

tijt_{ij}为第ii个串接在第jj个串之后重合的最大长度,暴力搜索所有可能性即可。
直接暴力搜会T,考虑记忆化搜索。设fijf_{ij}为最后一个串是第ii个串,jj的二进制位为每个串的使用情况的整个串的最小长度。只有当前的长度小于fijf_{ij}的时候才继续往下搜。
一个细节是如果把jj接在ii后面,ii恰好完全包含jj,那此时的最后一个串仍是ii,需要特判一下。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
#define tst
typedef long long ll;
typedef double db;
using namespace std;
const int INF=0x3f3f3f3f;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=16,M=101;
int n,ans=INF,rec;
int a[N][M],t[N][N],vis[N],f[N][1<<16];
#ifdef tst
void dfs(int lst,int tot)
{
	if(f[lst][rec]<=tot && f[lst][rec]!=0)
		return;
	f[lst][rec]=tot;
	if(tot>ans)
		return;
	int flag=0;
	rep(i,1,n)
	{
		if(vis[i])
			continue;
		flag=1;
		rec+=1<<(i-1);
		vis[i]=1;
		if(a[i][0]==t[lst][i])
			dfs(lst,tot);
		dfs(i,tot+a[i][0]-t[lst][i]);
		vis[i]=0;
		rec-=1<<(i-1);
	}
	if(!flag)
		ans=min(ans,tot);
}
#endif
void print()
{
	rep(i,1,n)
	{
		rep(j,1,n)
			cout<<i<<" "<<j<<" "<<t[i][j]<<endl;
		
	}
}
int main()
{
	scanf("%d",&n);
	rep(i,1,n)
	{
		scanf("%d",&a[i][0]);
		rep(j,1,a[i][0])
			scanf("%d",&a[i][j]);
	}
	rep(i,1,n)
	{
		rep(j,1,n)
		{
			if(i==j)
				continue;
			rep(k,1,a[i][0])
			{
				if(a[i][k]==a[j][1])
				{
					int indx=k,indy=1;
					int tog=1;
					while(indx<a[i][0] && indy<a[j][0])
					{
						if(a[i][indx+1]!=a[j][indy+1])
						{
							tog=0;
							break;
						}
						++indx;
						++indy;
						++tog;
					}
					if(indx==a[i][0] || indy==a[j][0])
					{
						t[i][j]=tog;
						break;
					}
				}
			}
		}
	}
#ifdef tst
	rep(i,1,n)
	{
		vis[i]=1;
		rec+=1<<(i-1);
		dfs(i,a[i][0]);
		rec-=1<<(i-1);
		vis[i]=0;
	}
#endif
	cout<<ans<<endl;
}