8.24总结


寿司

考场上我对于这道题第一眼感觉是DP(反正不会是数据结构),但n的数据范围太大了,我没有想到O(n)的DP。于是考虑是否是贪心,但考场上我推出的贪心式子有问题。我是通过枚举每一个连续位置,找出到达这个位置的步数,求步数的最小值,但我的贪心方法在找到达连续位置的步数时不是最优,所以错了。

综上,我与正解的差距过大,只有10pts。以下是正解的做法,因为是环上的问题,所以我们先把这个问题拆成链上的问题。在链上,我们很容易想到对于一个B的移动步数是向左移的步数和向右移的步数中较优的一个,所以设pos=(B的个数+1)/2,在pos左边的向左移,在pos右边的向右移,这样产生的步数一定是最优。

我们把上面的结论换到环上,因为环是循环结构,所以我们把给定的字符串复制一遍接在后面,预处理长为n*2的字符串的前缀和(分别为在前i个字符中R的个数/(l1_{i}/),在前i个字符中B的个数/(l2_{i}/),在后i个字符中R的个数/(r1_{i}/),在后i个字符中B的个数/(r2_{i}/))

我们先处理以第一个字符开头长为n的字符串,pos=(/(l2_{n}+1/))/2,然后按照链上的方法做,但因为pos会移动,需要记录第pos个B在字符串中的位置。在后面的字符串中,如果pos不移动则左边所有R的贡献减一,右边所有R贡献加一;如果移动pos下一个B就是pos,我们可以通过减去右边的B的数量,加上左边的B的数量来维护R的变动和当前状态的答案。最终答案取最小值。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
const int N=2e6+5;
int t,n,pos;
ll ans,res;
ll l1[N],l2[N],r1[N],r2[N];
char s[N];

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%s",s+1);
		n=strlen(s+1);
		for(re int i=1;i<=(n<<1);++i){
			l2[i]=l2[i-1],l1[i]=l1[i-1];
			if(s[(i-1)%n+1]=='R') ++l1[i];
			else ++l2[i];
		}
		for(re int i=(n<<1);i;--i){
			r2[i]=r2[i+1],r1[i]=r1[i+1];
			if(s[(i-1)%n+1]=='R')	++r1[i];
			else ++r2[i];
		}
		pos=(l2[n]+1)>>1;
		int p=-1;res=0;
		for(re int i=1;i<=n;++i){
			if(l2[i]==pos){
				p=i;
				for(re int j=n;j>=i;--j)
					if(s[j]=='R')
						res+=0ll+r2[j]-r2[n+1];
				break;
			}
			if(s[i]=='R')
				res+=0ll+l2[i];
		}
		re int l=1,r=n;
		ans=res;
		while(l<=n){
			if(s[(l-1)%n+1]=='B'){
				res-=0ll+l1[p]-l1[l-1];
				res+=0ll+r1[p]-r1[++r];
				++l;
				while(s[(++p-1)%n+1]=='R'){
					res+=0ll+l2[p]-l2[l-1];
					res-=0ll+r2[p]-r2[r+1];
				}
			}
			else ++l,++r;
			ans=min(ans,res);
		}
		printf("%lld/n",ans);
	}
	return 0;
}

最优序列

考场上我想到了DP,但没有想到状压DP。其实从/(m,k /leq 10/),就基本上可以猜到是状压DP,但因为对数据不敏感,我没有使用状压DP的意识,考场上我用了单调队列优化DP,过了大样例后就没管了,因此只有20pts

正解是用状压DP,先预处理出(1<<m)-1中可行的状态

岛屿

是一道基环树的模板题

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/282132.html

(0)
上一篇 2022年8月25日
下一篇 2022年8月25日

相关推荐

发表回复

登录后才能评论