Educational Codeforces Round 82

B. National Project(2s 256Mb)

题目大意

n块砖需要维修。如果在好天气里修变成好砖,在坏天气里变成坏砖。不一定每天都必须修砖。一开始先是连续g天好天气,又是连续b天坏天气,又是g天好天气,循环往复,求至少需要多少天,使得n块砖全部被修,且至少有\left \lceil \frac{n}{2} \right \rceil块砖是好砖。

分析

比赛时无限接近答案,不过还是没有太想清楚。题目要求我们满足两个条件,一个是n块砖全部被修,另一个是至少有\left \lceil \frac{n}{2} \right \rceil块砖是好砖。第一个说明答案至少是n。第二个我们只需要求得得到\left \lceil \frac{n}{2} \right \rceil好天气所需要的总天数,因为坏天气时可以选择不修。求法简单,用\left \lceil \frac{n}{2} \right \rceil除以g得到d,如过有剩余则是d*(g+b)+(\left \lceil \frac{n}{2} \right \rceil\mod g),否则是d*(g+b)-b,因为最后连续b天不需要。答案就是n与第二种中max的。


E. Erase Subsequences(2s 256Mb)

题目大意

给一个字符串s(4e2),目标字符串t。一开始你手里有一个空串,你可以从s中选择子序列,从s中删去,将序列排在你手里的串右边(+=),最多这样做两次。问可否得到最后的串。

分析

dp题。第一步我也想到,枚举t的分割点,前后字串为a,b,关键是如何在前后两次拿取不影响的情况下dp。令数组dp[lena][lenb]表示拿到a的前lena个,b的前lenb个字符需要的最少的lens,我们只幺预处理每个位置后每个字符第一次出现的位置即可O(1)向后更新。总复杂度O(n^3)

代码

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;
}

 

 

 

你可能感兴趣的:(字符串,动态规划)