zoukankan      html  css  js  c++  java
  • 2014百度之星复赛解题报告: FindNumbers

    FindNumbers
    时间限制:5s  内存限制:65536K

    问题描述:
    n个非负整数,满足对于某正整数kn=2^k-1。从中选出(n+1)/2个数,使得它们的和是(n+1)/2的倍数。

    输入
    第一行,T,询问个数。
    下面2T行,每两行是一个询问。对于每两行:
    第一行,n
    第二行,n个整数,a_0, a_1, ..., a_{n-1}

    1<=T<=20
    1<=n<=2^15
    0<=a_i<=10^9

    输出
    对第i个(1<=i<=T)询问的回答为两行,第一行为编号:
    Case #i:
    第二行为结果:
    如果不能选出这样的(n+1)/2个数,输出-1
    否则输出一行,用一个空格分隔的(n+1)/2个数b_0, b_1, ..., b_{(n+1)/2-1}。满足b_i两两不同,且sum(a_{b_i})(n+1)/2的倍数。如果有多解,输出任意一个。

    样例输入
    2
    3
    1 3 5
    7
    0 1 2 3 4 5 6
    样例输出
    Case #1:
    0 2
    Case #2:
    0 2 4 6

    解题报告 – FindNumbers

    鉴于n=2^k-1(k为正整数),因此由归纳法可证明必有解。
    证明:
    归纳基础:对于k=1,显然成立,
    归纳假设:假定对于任意正整数k,有解。
    归纳推理:考虑对于n=2^(k+1)-1的情形,我们可以将a[0..n-1]分为a[0..2^k-2]a[2^k-1..n-2], 由归纳假设可得:
    从a[0..2^k-2]中我们可以挑出(m+1)/2个数b1[0..(m-1)/2], 满足sum{b1[0..(m-1)]}=r*(m+1)/2,其中m=2^k-1,r为某个非负整数。
    从a[2^k-1..n-2]中我们可以挑出(m+1)/2个数b2[0..(m-1)/2], 满足sum{b2[0..(m-1)]}=s*(m+1)/2,其中m=2^k-1,s为某个非负整数。
    从a-b1-b2中(含|a-b1-b2|=m个非负整数)我们可以挑出(m+1)/2个数b3[0..(m-1)/2], 满足sum{b3[0..(m-1)]}=t*(m+1)/2,其中m=2^k-1,t为某个非负整数。
    由于r,s,t三个非负整数中必有两个奇偶性相同,从而{(r+s),(s+t),(r+t)}中必有某个为2的倍数。若(r+s)%2==0, 则可将b1和b2合并得到m+1=(n+1)/2个非负整数且sum{b1,b2}=(r+s)*(m+1)/2=(r+s)/2*(m+1)=(r+s)/2*(n+1)/2,为(n+1)/2的倍数。其他情况同理可得。
                                                                                                                                                         证毕
    由上述证明,可得到分治算法,先将a分为a[0..(n-1)/2-1]和a[(n-1)/2..n-2],递归分别求得b1和b2, 如果sum{b1+b2}满足条件,则返回,否则对a-b1-b2递归,求得b3,如果sum{b1+b3}满足条件,则返回,否则sum{b2+b3}必满足条件,返回。易见该算法复杂度为O(nlogn)。


    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cassert>
    #include <ctime>
    #include <set>
    #include <map>
    #include <vector>
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    //#include <sys/time.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<int,int> PII;
    
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    
    typedef pair<vector<int>, int> PVI; 
    
    #define N 65555
    int a[N]; 
    
    vector<int> comb(const vector<int>&a, const vector<int>&b) {
            vector<int> c; 
            int l = 0, r = 0; int n = (int) a.size(); 
            while (l < n && r < n) {
                    if (a[l] < b[r]) c.pb(a[l++]); 
                    else c.pb(b[r++]); 
            }
            while (l < n) c.pb(a[l++]);
            while (r < n) c.pb(b[r++]);
            
            return c; 
    }
    
    PVI ff(const vector<int>&p) {
            int n = (int) p.size(); int m = (n+1)/2; 
            if (n == 1) return mp(p, a[p[0]]); 
            vector<int> p1, p2; 
            for (int i = 0; i < n/2; i ++) p1.pb(p[i]); 
            for (int i = n/2; i < n-1; i ++) p2.pb(p[i]); 
            PVI s1 = ff(p1), s2 = ff(p2); 
            if ((s1.se + s2.se) % m == 0) return mp(comb(s1.fi, s2.fi), s1.se + s2.se); 
            
            vector<int> p3; int l = 0, r = 0; 
            
            for (int i = 0; i < n; i ++) {
                    while (l < (n+1)/4 && s1.fi[l] < p[i]) l ++; 
                    while (r < (n+1)/4 && s2.fi[r] < p[i]) r ++; 
                    if ((l == (n+1)/4 || s1.fi[l] > p[i]) && (r == (n+1)/4 || s2.fi[r] > p[i])) p3.pb(p[i]);
            }
            
            PVI s3 = ff(p3); 
            if ((s1.se + s3.se) % m == 0) return mp(comb(s1.fi, s3.fi), s1.se + s3.se); 
            if ((s2.se + s3.se) % m == 0) return mp(comb(s2.fi, s3.fi), s2.se + s3.se); 
    }
    
    int main()
    {
    //    timeval start;
    //    gettimeofday(&start, NULL);
        int T;
            scanf("%d", &T); 
        for (int c = 1; c <= T; ++c) {
                    int n; scanf("%d", &n); 
                    int m = (n+1)/2; 
                    for (int i = 0; i < n; i ++)
                            scanf("%d", a+i), a[i] %= m; 
                    vector<int> p; 
                    for (int i = 0; i < n; i ++) 
                            p.pb(i); 
                    vector<int> s = ff(p).fi; 
            printf("Case #%d:
    ", c);
                    for (int i = 0; i < (n+1)/2; i ++) 
                            printf ("%d%c", s[i], i == n/2 ? '
    ': ' '); 
            }
     //   timeval end;
     //   gettimeofday(&end, NULL);
     //   double duration = ((long long) end.tv_sec * 1000000 + end.tv_usec - (long long) start.tv_sec * 1000000 + start.tv_usec) / 1000000.0;
     //   fprintf(stderr, "%.1fsec
    ", duration);
            return 0;
    }


  • 相关阅读:
    基因id转换
    Trinity的分步运行
    免费的稳定的SVN托管的服务器
    游戏化
    一个华裔男孩在美国的成长之路
    你懂USB和Type-C吗
    ios调试小技巧
    swift开发笔记19
    iOS 3DTouch应用
    iCloud实现APP多设备数据同步
  • 原文地址:https://www.cnblogs.com/hosealeo/p/4190493.html
Copyright © 2011-2022 走看看