B. National Project(2s 256Mb)
题目大意
有块砖需要维修。如果在好天气里修变成好砖,在坏天气里变成坏砖。不一定每天都必须修砖。一开始先是连续
天好天气,又是连续
天坏天气,又是
天好天气,循环往复,求至少需要多少天,使得
块砖全部被修,且至少有
块砖是好砖。
分析
比赛时无限接近答案,不过还是没有太想清楚。题目要求我们满足两个条件,一个是n块砖全部被修,另一个是至少有块砖是好砖。第一个说明答案至少是n。第二个我们只需要求得得到
好天气所需要的总天数,因为坏天气时可以选择不修。求法简单,用
除以
得到
,如过有剩余则是
,否则是
,因为最后连续
天不需要。答案就是
与第二种中
的。
E. Erase Subsequences(2s 256Mb)
题目大意
给一个字符串,目标字符串
。一开始你手里有一个空串,你可以从
中选择子序列,从
中删去,将序列排在你手里的串右边(+=),最多这样做两次。问可否得到最后的串。
分析
dp题。第一步我也想到,枚举的分割点,前后字串为
,关键是如何在前后两次拿取不影响的情况下dp。令数组
表示拿到
的前
个,
的前
个字符需要的最少的
,我们只幺预处理每个位置后每个字符第一次出现的位置即可
向后更新。总复杂度
。
代码
int work()
{
memset(dp, 63, sizeof(dp));
dp[0][0] = 0;
for(int i = 0; i <= lena; i++)
for(int j = 0; j <= lenb; j++) if(dp[i][j] < lens)
{
// 更新状态,nt为预处理的位置
if(i < lena) dp[i+1][j] = min(dp[i+1][j], nt[t[i+1]][dp[i][j]+1]);
if(j < lenb) dp[i][j+1] = min(dp[i][j+1], nt[t[lena+j+1]][dp[i][j]+1]);
}
return dp[lena][lenb] <= lens; // 判断能否完成
}
int main()
{
int T = read(); while(T--)
{
cle();
in(s, lens); in(t, lent);
for(int i = 1; i <= 26; i++)
for(int j = lens; j; j--) nt[i][j] = (s[j]==i) ? j : nt[i][j+1]; // 预处理
int flag = 0;
for(lena = 1; lena <= lent; lena++) // 枚举分割点
{
lenb = lent-lena;
if(work())
{
printf("YES\n");
flag = 1;
break;
}
}
if(!flag) printf("NO\n");
}
return 0;
}