POJ 3276 尺取

输入样例

7

BBFBFBB

B为牛的头向后,F为牛的头向前。现在买一台机子可以把连续k头牛转头,问最小转的次数和最小应该买的机子的k。

必须严格k头转,k=3时候,不会出现只转最后一头或最后3头。

可以显然得出从第i头牛反转0次的结果与反转2次是相同的,反转1次与反转3次是相同的。那么从第i头牛开始反转的次数要么为0要么为1。

然后反转的顺序对最终结果是不影响的,那么可以从最左边开始推。

第一头牛如果为B,则其必定反转,第一头牛如果为F,则其必定不反转,然后根据上面的性质,对第二头牛有影响的操作只有反转/不反转从i=2开始的反转,

以此类推可以得到

for(i=0;i+k<=l1;i++){
    		if(s2[i]=='B'){
    			t1++;
    			for(j=i;j<i+k;j++){
    				if(s2[j]=='B')s2[j]='F';
    				else s2[j]='B';
				}
			}
		}
但是这么做为O(N^3)显然超时,从左扫到右时,对第i头牛反转的次数为第i-k+1到i-1的反转次数和,那么可以用尺取的办法加之前k-1头牛的反转次数来判断这头牛是否该反转,

这样就可以做到对每个k只需要线性扫描就可以得知其开头的这次反转是否需要。

wa-1  没考虑必须每次严格反转k次

wa-2 没考虑到第i(i<k)头牛的时候虽然是B但是其前面放反转过一次就不需要再进行反转了。我之前的判断是遇到B都反转

wa-3 我在下面的else if 才进行if(i+k>l1){break;}, 这是错误的,有可能i在小于k的时候就不能严格反转k个了。

important points:1、尺取用在与区间相关的地方,其像个尺子一样记录连续k个值。

#include <queue>
#include<iostream>
#include<stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <ctime> 
using namespace std;
struct ttt{
	double x1,y1,x2,y2;
};
ttt qq[105];
char s1[10500];
int f[5050];
int f2[5050];
int main(){
//	freopen("in.txt","r",stdin);
	//freopen("output.txt","w",stdout);
    int i,j,k,l,f1,f3,t1,t2,t3,m;
    int l1,l2,l3,f4,f5;
    int n,sum1;
    int tt=0;
    cin >> l1;
	for(i=0;i<l1;i++){
	scanf("%c",&s1[i]);
	if(s1[i]=='\n'||s1[i]=='\0'){
		i--;continue;
	}
} 
    int min1=1e9;
    for(k=1;k<=l1;k++){
    	t1=0;
		memset(f,0,sizeof(f));
		t2=0;
		t3=0;
		for(i=0;i<l1;i++){
		f2[i]=0;  //Ϊ0±íʾûÓз´×ª 
		if(i+k>l1){
			break;
		}
		if(i<k-1){
		if(s1[i]=='B'&&t1%2==0){
		f[i]=1;t2++;
		f2[i]=1;
		}else if(s1[i]=='F'&&t1%2==1){
		f[i]=1;t2++;
		f2[i]=t1+1;
		}else{
		f2[i]=t1;
		}
		t1+=f[i];
		}else{
		if(t1%2==0&&s1[i]=='B'){
		f[i]=1;t2++;f2[i]=t1+1;  //û·´×ªÇÒÓ¦¸Ã·´×ª¡£ 
		}else if(t1%2==1&&s1[i]=='F'){ //²»¸Ã·´×ªÈ´·´×ªÁË 
		f[i]=1;t2++;f2[i]=t1+1;
		}else{
		f2[i]=t1;
		}
		t1+=f[i];
		t1-=f[i-k+1];
		}
	//	cout << f2[i] << "   "<< "   " << t1<<endl;
		if((f2[i]%2==0&&s1[i]=='B')||(f2[i]%2==1&&s1[i]=='F')){
		t3=1;     //û·´×ª/²»¸Ã·´×ª 
		}
	//	cout << k << "   ÔÚ "  <<i << "  µØ·½" << t3 << endl;
	}
		for(j=i;j<l1;j++){
		f2[j]=t1;
		t1-=f[j-k+1];	
		if((f2[j]%2==0&&s1[j]=='B')||(f2[j]%2==1&&s1[j]=='F')){
		t3=1;     //û·´×ª/²»¸Ã·´×ª 
		}
	//	cout << k << "   ÔÚ "  <<j << "  µØ·½" << t3 << endl;
		}
		if(t3==0&&t2<min1){
	//	cout << k << "ÊÇÕýÈ·µÄ" << endl;
		min1=t2;
		f5=k;
		}
	}
	cout << f5 << " "<< min1  <<endl;
  	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值