TopCoder SRM 612 DIV1 900

题意:

n个人坐成一圈,每个人绑起一只手,用L和R表示。如果一个R坐在L左边则会产生一个冲突。每次操作可将相邻两个人交换位置,求操作至冲突最少所需的最少次数。

题解:

如果只有L或只有R,则无冲突,否则冲突最小时是L连成一片,R连成一片,冲突为1.

可以单独考虑将L挪到一块去。枚举位置l,表示所有的L都向l挪,那么肯定一部分往后,一部分往前最优

可以找到一个位置r,l~r间的L往后,其它的往前,这样费用最小

对于l+1,新的r肯定也在原来的r后面(要考虑r从n-1变成0的情况),所以实际上就是维护两个指针而已

根据l和r的分开讨论就可以算出来了


其实我的代码还有问题,原本我是只考虑L的,现在是L和R各做一次取最小,否则过不了,不知道为什么,哪位高人看出来了请指点一下,感激不尽


import java.util.*;
public class LeftAndRightHandedDiv1
{
	final int MAXN = 1000010;
	long []psum=new long [MAXN];
	int []lcnt=new int [MAXN];
	long cal(int start,int num)
	{
		return (long)(start+start+num-1)*num/2;
	}
	boolean check(int r,int l,int n)
	{
		if(r>n)	r=0;
		int lnum=0,left;
		if(r>=l)
			lnum=lcnt[r]-lcnt[l-1];
		else	lnum=lcnt[n]-lcnt[l-1]+lcnt[r];
		left=lcnt[n]-lnum;
		return (r+n-l)%n-(lnum-1)<=(l+n-r-1)%n-(left-1);
	}
	long _countSwaps(String t,int n,char whi)
	{
		long ans=Long.MAX_VALUE;
		lcnt[0]=0;
		psum[0]=0;
		for(int i=1;i<=n;++i)
		{
			lcnt[i]=lcnt[i-1];
			psum[i]=psum[i-1];
			if(t.charAt(i-1)==whi)
			{
				++lcnt[i];
				psum[i]+=i;
			}
		}
		if(lcnt[n]==n||lcnt[n]==0)
			return 0;
		int lnum=0,left=lcnt[n];
		if(t.charAt(0)==whi)
		{
			++lnum;
			--left;
		}
		for(int l=1,r=1;l<=n;++l)
		{
			while(check(r+1,l,n))
			{
				++r;
				if(r>n)
					r=1;
				if(t.charAt(r-1)==whi)
				{
					++lnum;
					--left;
				}
				if(left==0)	break;
			}
			long tmp=0;
			if(r>=l)
				tmp+=(psum[r]-psum[l-1])-cal(l,lnum);
			else	tmp+=(psum[r]+(long)lcnt[r]*n)+(psum[n]-psum[l-1])-cal(l,lnum);
			if(r>=l)
				tmp+=cal(l+n-left,left)-(psum[n]-psum[r])-(psum[l-1]+(long)n*lcnt[l-1]);
			else	tmp+=cal(l-left,left)-(psum[l-1]-psum[r]);
			ans=Math.min(ans, tmp);
			if(t.charAt(l-1)==whi)
			{
				--lnum;
				++left;
			}
		}
		return ans;
	}
	public long countSwaps(String Y,int a,int b,int c,int d,int n)
	{
		long pre=a;
		StringBuffer t=new StringBuffer();
		for(int i=0;i<n;++i)
		{
			t.append(Y.charAt((int)pre%Y.length()));
			pre=(pre*b+c)%d;
		}
		return Math.min(_countSwaps(t.toString(), n,'L'), _countSwaps(t.toString(), n,'R'));
	}
	public static void main(String []args)
	{
		LeftAndRightHandedDiv1 lef=new LeftAndRightHandedDiv1();
		Scanner scan=new Scanner(System.in);
		while(scan.hasNext())
		{
			String y=scan.next();
			int a,b,c,d,n;
			a=scan.nextInt();
			b=scan.nextInt();
			c=scan.nextInt();
			d=scan.nextInt();
			n=scan.nextInt();
			System.out.println(lef.countSwaps(y, a, b, c, d, n));
		}
		scan.close();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值