Codeforces Round #956 (Div. 2) C. Have Your Cake and Eat It Too

Codeforces Round #956 (Div. 2)

C.Have Your Cake and Eat It Too

题目大意:

有长度为 n n n的数组 a , b , c a,b,c a,b,c,三个数组的和相同,把 n n n分为三段非空连续段 [ l a , r a ] , [ l b , r b ] , [ l c , r c ] [l_a,r_a],[l_b,r_b],[l_c,r_c] [la,ra],[lb,rb],[lc,rc],互不重合。
保证 ∑ i = l a r a a i , ∑ i = l b r b b i , ∑ i = l c r c c i > = k \sum_{i=l_a}^{r_a}a_i,\sum_{i=l_b}^{r_b}b_i,\sum_{i=l_c}^{r_c}c_i >=k i=laraai,i=lbrbbi,i=lcrcci>=k
k k k是大于等于 ∑ i = 1 n a i n \frac{\sum_{i=1}^{n}a_i}{n} ni=1nai的整数
输出 l a , r a , l b , r b , l c , r c l_a,r_a,l_b,r_b,l_c,r_c la,ra,lb,rb,lc,rc,如果无法分就输出-1

解题思路:

考虑三种可能性
1. [ l a , r a ] [l_a,r_a] [la,ra]在1-n左边,就是 a b c / a c b abc/acb abc/acb
2. [ l a , r a ] [l_a,r_a] [la,ra]在1-n右边,就是 b c a / c b a bca/cba bca/cba
3. [ l a , r a ] [l_a,r_a] [la,ra]在1-n中间,就是 b a c / c a b bac/cab bac/cab
先前缀和一遍,方便计算子数组的和
可能性1:
遍历 l a = 1 l_a=1 la=1,遍历1-n,找到最小的 r a r_a ra,然后在 [ r a + 1 , n ] [r_a+1,n] [ra+1,n],遍历每个位置,判断一下 b b b c c c的子数组和是否满足 > = k >=k >=k

	for(int i=1;i<n-1;i++){
		if(a[i]>=k){
			s1=i;
			break;
		}
	}
	for(int i=s1+1;i<n;i++){
		if(b[i]-b[s1]>=k&&c[n]-c[i]>=k){
			cout<<1<<' '<<s1<<' '<<s1+1<<' '<<i<<' '<<i+1<<' '<<n<<'\n';
			return  ;
		}
		if(c[i]-c[s1]>=k&&b[n]-b[i]>=k){
			cout<<1<<' '<<s1<<' '<<i+1<<' '<<n<<' '<<s1+1<<' '<<i<<'\n';
			return  ;
		}
	}

可能性1:
遍历 r a = n r_a=n ra=n,遍历n-1,找到最大的 l a l_a la,然后在 [ 1 , l a − 1 ] [1,l_a-1] [1,la1],遍历每个位置,判断一下 b b b c c c的子数组和是否满足 > = k >=k >=k

	for(int i=n;i>2;i--){
		if(a[n]-a[i-1]>=k){
			s1=i;
			break;
		}
	}
	for(int i=1;i<s1-1;i++){
		if(b[i]>=k&&c[s1-1]-c[i]>=k){
			cout<<s1<<' '<<n<<' '<<1<<' '<<i<<' '<<i+1<<' '<<s1-1<<'\n';
		return ;
		}
		if(c[i]>=k&&b[s1-1]-b[i]>=k){
			cout<<s1<<' '<<n<<' '<<i+1<<' '<<s1-1<<' '<<1<<' '<<i<<'\n';
		return ;
		}
	}

可能性3:
遍历2-(n-1),枚举每个节点为 l a l_a la,二分找满足条件的最小 r a r_a ra,再判断两边的 b b b c c c的子数组和是否满足 > = k >=k >=k

	int s1,s2,s3,l,r,mid;
	for(int i=2;i<n;i++){
		l=i,r=n;
		while(l<r){
			mid=(l+r)/2;
			if(a[mid]-a[i-1]<k)l=mid+1;
			else r=mid;
		}
		if(a[l]-a[i-1]>=k){
			if(b[i-1]>=k&&c[n]-c[l]>=k){
				cout<<i<<' '<<l<<' '<<1<<' '<<i-1<<' '<<l+1<<' '<<n<<'\n';
				return ;
			}
			if(c[i-1]>=k&&b[n]-b[l]>=k){
				cout<<i<<' '<<l<<' '<<l+1<<' '<<n<<' '<<1<<' '<<i-1<<'\n';
				return ;
			}
		}
	}

最后都没有满足的就输出-1
完整代码如下:

#include
#define int long long
using namespace std;

const int N=2e5+6;
int a[N],b[N],c[N];

void solve()
{
	int n,sum=0;
	cin>>n;
	a[0]=0,b[0]=0,c[0]=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		a[i]+=a[i-1];
		sum+=a[i];
	}
	for(int i=1;i<=n;i++){
		cin>>b[i];
		b[i]+=b[i-1];
	}
	for(int i=1;i<=n;i++){
		cin>>c[i];
		c[i]+=c[i-1];
	}
	int k=a[n]/3;
	if(a[n]%3)k++;
	int s1,s2,s3,l,r,mid;
	for(int i=2;i<n;i++){
		l=i,r=n;
		while(l<r){
			mid=(l+r)/2;
			if(a[mid]-a[i-1]<k)l=mid+1;
			else r=mid;
		}
		if(a[l]-a[i-1]>=k){
			if(b[i-1]>=k&&c[n]-c[l]>=k){
				cout<<i<<' '<<l<<' '<<1<<' '<<i-1<<' '<<l+1<<' '<<n<<'\n';
				return ;
			}
			if(c[i-1]>=k&&b[n]-b[l]>=k){
				cout<<i<<' '<<l<<' '<<l+1<<' '<<n<<' '<<1<<' '<<i-1<<'\n';
				return ;
			}
		}
	}
	for(int i=1;i<n-1;i++){
		if(a[i]>=k){
			s1=i;
			break;
		}
	}
	for(int i=s1+1;i<n;i++){
		if(b[i]-b[s1]>=k&&c[n]-c[i]>=k){
			cout<<1<<' '<<s1<<' '<<s1+1<<' '<<i<<' '<<i+1<<' '<<n<<'\n';
			return  ;
		}
		if(c[i]-c[s1]>=k&&b[n]-b[i]>=k){
			cout<<1<<' '<<s1<<' '<<i+1<<' '<<n<<' '<<s1+1<<' '<<i<<'\n';
			return  ;
		}
	}
	for(int i=n;i>2;i--){
		if(a[n]-a[i-1]>=k){
			s1=i;
			break;
		}
	}
	for(int i=1;i<s1-1;i++){
		if(b[i]>=k&&c[s1-1]-c[i]>=k){
			cout<<s1<<' '<<n<<' '<<1<<' '<<i<<' '<<i+1<<' '<<s1-1<<'\n';
		return ;
		}
		if(c[i]>=k&&b[s1-1]-b[i]>=k){
			cout<<s1<<' '<<n<<' '<<i+1<<' '<<s1-1<<' '<<1<<' '<<i<<'\n';
		return ;
		}
	}
	cout<<"-1\n";
}
signed main()
{

    int T;
    cin>>T;
    while(T--)
    {;
        solve();
    }
    return 0;
}

你可能感兴趣的:(c语言,算法,开发语言)