zoukankan      html  css  js  c++  java
  • 【CF618F】Double Knapsack

    题目

    题目链接:https://codeforces.com/problemset/problem/618/F

    给你两个可重集 \(A,B\),\(A,B\) 的元素个数都为 \(n\)\(n⩽1000000\),它们中每个元素的大小 \(x∈[1,n]\)。请你分别找出 \(A,B\) 的可重子集,使得它们中的元素之和相等。

    思路

    记两个数组的前缀和分别为 \(a,b\),设 \(a[n]\geq b[n]\)。对于每一个 \(a[i]\),求出小于 \(a[i]\) 且最接近 \(a[i]\)\(b[j]\),令 \(c[i]\) 表示 \(a[i]-b[j]\)

    如果存在两个 \(c[i]\)\(c[j]\) 相等,那么就一定存在答案。由于 \(0\leq c< n\),而一共有 \(c[0]\sim c[n]\)\(n+1\) 个不同的答案,所以一定有答案,且一定有连续的答案。

    时间复杂度 \(O(n)\)

    代码

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=1000010;
    int n,pos[N][2];
    ll a[N],b[N];
    bool flag;
    
    ll read()
    {
    	ll d=0; char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    int main()
    {
    	n=read();
    	for (int i=1;i<=n;i++)
    		a[i]=a[i-1]+read();
    	for (int i=1;i<=n;i++)
    		b[i]=b[i-1]+read();
    	if (a[n]<b[n])
    	{
    		for (int i=1;i<=n;i++)
    			swap(a[i],b[i]);
    		flag=1;
    	}
    	memset(pos,-1,sizeof(pos));
    	for (int i=0,j=0;i<=n;i++)
    	{
    		while (j<n && a[i]>=b[j+1]) j++;
    		int k=a[i]-b[j];
    		if (pos[k][0]>=0)
    		{
    			if (flag) swap(i,j),swap(pos[k][0],pos[k][1]);
    			printf("%d\n",i-pos[k][0]);
    			for (int l=pos[k][0]+1;l<=i;l++) printf("%d ",l);
    			printf("\n%d\n",j-pos[k][1]);
    			for (int l=pos[k][1]+1;l<=j;l++) printf("%d ",l);
    			return 0;
    		}
    		pos[k][0]=i; pos[k][1]=j;
    	}
    	return 0;
    }
    
  • 相关阅读:
    SpringMVC 工作流程
    zookeeper
    Zookeeper
    HashMap
    Shiro learning
    Shiro learning
    Shiro learning
    Easy Poi入门
    Enum枚举学习- java5之前和之后的写法
    linux命令行todo列表管理工具Taskwarrior介绍
  • 原文地址:https://www.cnblogs.com/stoorz/p/12979494.html
Copyright © 2011-2022 走看看