zoukankan      html  css  js  c++  java
  • CF618F Double Knapsack 构造、抽屉原理

    传送门


    首先,选取子集的限制太宽了,子集似乎只能枚举,不是很好做。考虑加强限制条件:将“选取子集”的限制变为“选取子序列”的限制。在接下来的讨论中我们将会知道:将限制控制得更紧,问题也一定会有解。

    现在我们需要求(A,B)的两个子序列,满足两者的和相等。显然可以前缀和,然后就不会做了qwq

    考虑下面的算法:假定(sumlimits_{a in A} a < sumlimits_{b in B} b)(如果相等直接全选),设序列(A)前缀和为(sumA_i),序列(B)前缀和为(sumB_i)

    对于(n+1)(sumA_i),在(sumB)中找到最小的大于等于它的元素(sumB_j),那么一定有(sumB_j - sumA_i in [0,n)),可能的(sumB - sumA)(n)种,但是有(n+1)(i,j)

    根据抽屉原理,一定会存在两组((i_1,j_1)(i_2,j_2)(i_1 > i_2))满足(sumB_{j_1} - sumA_{i_1} = sumB_{j_2} - sumA_{i_2}),即(sumB_{j_1} - sumB_{j_2} = sumA_{i_1} - sumA_{i_2})。这样我们就找到了一组可行解:在(A)中选择(A_x , x in (i_2 , i_1]),在(B)中选择(B_y , y in (j_2 , j_1])

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #include<cctype>
    #include<algorithm>
    #include<cstring>
    #include<iomanip>
    #include<queue>
    #include<map>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<stack>
    #include<cmath>
    #include<random>
    //This code is written by Itst
    using namespace std;
    
    inline int read(){
    	int a = 0;
    	char c = getchar();
    	bool f = 0;
    	while(!isdigit(c) && c != EOF){
    		if(c == '-')
    			f = 1;
    		c = getchar();
    	}
    	if(c == EOF)
    		exit(0);
    	while(isdigit(c)){
    		a = a * 10 + c - 48;
    		c = getchar();
    	}
    	return f ? -a : a;
    }
    
    #define PII pair < int , int >
    #define st first
    #define nd second
    #define ll long long
    const int MAXN = 1e6 + 7;
    ll A[MAXN] , B[MAXN];
    PII pos[MAXN];
    
    signed main(){
    #ifndef ONLINE_JUDGE
    	freopen("in","r",stdin);
    	//freopen("out","w",stdout);
    #endif
    	int 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();
    	bool f = A[N] > B[N];
    	if(f) swap(A , B);
    	fill(pos , pos + N + 1 , PII(-1 , -1));
    	int p = 0;
    	for(int i = 0 ; i <= N ; ++i){
    		while(B[p] < A[i]) ++p;
    		if(pos[B[p] - A[i]] != PII(-1 , -1)){
    			PII t = pos[B[p] - A[i]];
    			if(!f){
    				printf("%d
    " , i - t.first);
    				for(int j = t.first + 1 ; j <= i ; ++j)
    					printf("%d " , j);
    				printf("
    %d
    " , p - t.second);
    				for(int j = t.second + 1 ; j <= p ; ++j)
    					printf("%d " , j);
    			}
    			else{
    				printf("%d
    " , p - t.second);
    				for(int j = t.second + 1 ; j <= p ; ++j)
    					printf("%d " , j);
    				printf("
    %d
    " , i - t.first);
    				for(int j = t.first + 1 ; j <= i ; ++j)
    					printf("%d " , j);
    			}
    			return 0;
    		}
    		else pos[B[p] - A[i]] = PII(i , p);
    	}
    	puts("-1");
    	return 0;
    }
    
  • 相关阅读:
    Hard Rock
    Codeforces Round #416 (Div. 2) B. Vladik and Complicated Book
    codeforces 793B. Igor and his way to work
    codeforces 1B Spreadsheets
    HDU 1069 Monkey and Banana
    codeforces 2B The least round way
    【机器学习】 通俗说拟合
    python-八皇后问题
    python-核心知识思维导图
    python-@property 属性
  • 原文地址:https://www.cnblogs.com/Itst/p/10585514.html
Copyright © 2011-2022 走看看