CF1512D Corrupted Array 题解

Posted yuhang-ren

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1512D Corrupted Array 题解相关的知识,希望对你有一定的参考价值。

CF1512D Corrupted Array 题解

CF1512D Corrupted Array 题解

洛谷

Codeforces

Description

给定一个正整数 \\(n\\) 和长度为 \\(n+2\\) 的数组 \\(b\\),数组 \\(b\\) 是依据如下算法构造的:

  • 随机生成一个含有 \\(n\\) 个元素的原始数组\\(a\\)
  • 把数组 \\(a\\) 赋值给数组 \\(b\\),即 \\(b_i=a_i(1\\le i\\le n)\\)
  • 数组 \\(b\\) 的第 \\(n+1\\) 个元素为数组 \\(a\\) 的元素和,即 \\(b_n+1=\\sum_i=1^na_i\\)
  • 数组 \\(b\\) 的第 \\(n+2\\) 个元素是个随机整数 \\(x(1\\le x\\le10^9)\\)
  • 打乱 \\(b\\) 数组。

例如,数组 \\(b=[2,3,7,12,2]\\),那么它能够通过如下方式构建:

  • \\(a=[2,2,3]\\),且 \\(x=12\\)
  • \\(a=[3,2,7]\\),且 \\(x=2\\)

给定一个 \\(b\\) 数组,请你求出它对应的 \\(a\\) 数组。

Solution

假设打乱前的 \\(b\\) 数组为 \\(c\\),记所有数的和为 \\(sum\\)

\\(b\\) 数组排序,为了满足数组 \\(c\\) 的第 \\(n+1\\) 个元素为数组 \\(a\\) 的元素和,和一定为最大的数或第二大的数(此时对应的随机数为最大的数)。

在排序后的 \\(b\\) 数组中枚举随机数,设当前位置为 \\(i\\)

  • \\(i = n + 2\\) 时,\\(sum - b_n + 2 - b_n + 1 = b_n + 1\\) 时满足条件,此时输出 \\(b_1,\\ldots,b_n\\) 即可。

  • 否则当 \\(sum - b_n + 2 - b_i = b_n + 2\\) 时满足条件,此时对于所有的 \\((1 \\leq k \\leq n + 1)\\)\\(k \\ne i\\) 输出 \\(b_k\\) 即可。

全部枚举仍无答案则无解。

Codes

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define max_n 300010
void read(int &p)

    p = 0;
    int k = 1;
    char c = getchar();
    while (c < \'0\' || c > \'9\')
    
        if (c == \'-\')
        
            k = -1;
        
        c = getchar();
    
    while (c >= \'0\' && c <= \'9\')
    
        p = p * 10 + c - \'0\';
        c = getchar();
    
    p *= k;
    return;

void write_(int x)

    if (x < 0)
    
        putchar(\'-\');
        x = -x;
    
    if (x > 9)
    
        write_(x / 10);
    
    putchar(x % 10 + \'0\');

void writesp(int x)

    write_(x);
    putchar(\' \');

void writeln(int x)

    write_(x);
    putchar(\'\\n\');

int T, n, nums[max_n];
signed main()

#if _clang_
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    read(T);
    while (T--)
    
        read(n);
        int sum = 0;
        for (int i = 1; i <= n + 2; i++)
        
            read(nums[i]);
            sum += nums[i];
        
        sort(nums + 1, nums + n + 3);
        if (sum - nums[n + 2] - nums[n + 1] == nums[n + 1] || sum - nums[n + 2] - nums[n + 1] == nums[n + 2])
        
            for (int i = 1; i <= n; i++)
            
                writesp(nums[i]);
            
            puts("");
            continue;
        
        int ans = -1;
        for (int i = 1; i <= n; i++)
        
            if (sum - nums[n + 2] - nums[i] == nums[n + 2])
            
                ans = i;
                continue;
            
        
        if (ans == -1)
        
            puts("-1");
            continue;
        
        else
        
            for (int i = 1; i <= n + 1; i++)
            
                if (i == ans)
                
                    continue;
                
                writesp(nums[i]);
            
            puts("");
        
    
    return 0;

IndiaHacks 2016 - Online Edition (CF) . D

这题思路很简单,二分m,求最大流是否大于等于x。

但是比赛过程中大部分的代码都被hack了。。。

精度问题,和流量可能超int

关于精度问题,这题真是提醒的到位,如果是先用二分将精度控制在10^-8左右,最后乘一个10^4,精度只能在10-4,而二分控制精度在10^-11很容易死循环(因为double 保存15-16位有效数字,结果可能为10^6级,精确到10-11,double做不到)

所以这题二分可以不写成while(d-b>eps),而直接规定二分的次数,设置成100次,基本可以保证14-15位有效数字都正确了,这时再乘10^4还是能够达到题目中要求的10^-6的精度。

还有一种处理精度的方法:

直接定义上下界就为输出的最后结果,在判断的过程中除以x,最后输出也能满足要求。

第一种精度处理方式:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <iostream>
using namespace std;
#define eps 1e-11
#define N 55
#define M 500500
#define INF 0x3fffff



struct node1
{
    long long to,w,next;
}edge[M];

long long sn,sm,sx;
long long pre[10*N];
long long g[N][N];
long long gap[10*N],lv[10*N];
long long k,c,m;
long long cnt;
long long n,nn;
long long s,t;
long long ans;
long long sum;


void add_edge(long long u,long long v,long long w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
}

long long gdfs(long long k,long long w)
{
    if(k==t) return w;
    long long f=0;
    long long mi=nn-1;
    for(long long p=pre[k];p!=-1;p=edge[p].next)
    {
        long long v=edge[p].to,tw=edge[p].w;
        if(tw!=0)
        {
            if(lv[k]==lv[v]+1)
            {
                long long tmp=gdfs(v,min(tw,w-f));
                f+=tmp;
                edge[p].w-=tmp;
                edge[p^1].w+=tmp;
                if(f==w||lv[s]==nn) break;
            }
            if(lv[v]<mi) mi=lv[v];
        }
    }
    if(f==0)
    {
        gap[lv[k]]--;
        if( gap[ lv[k] ]==0 )
        {
            lv[s]=nn;
        }
        lv[k]=mi+1;
        gap[lv[k]]++;
    }
    return f;
}

long long sap()
{
    memset(lv,0,sizeof(lv));
    memset(gap,0,sizeof(gap));
    gap[0]=nn;
    while(lv[s]<nn)
    {
        sum+=gdfs(s,INF);
    }
    return sum;
}

long long a[505],b[505],kk[505];

long long check(double mid)
{
    sum=0;
    //mid/=sx;
    memset(pre,-1,sizeof(pre));
    cnt=0;
    
    for(long long i=0;i<sm;i++)
    {
        add_edge(a[i],b[i],(long long)(kk[i]/mid+eps));
        add_edge(b[i],a[i],0);
    }
    if(sap()>=sx)
    {
        return 1;
    }
    else return 0;
}



int main()
{
    cin>>sn>>sm>>sx;
    for(long long i=0;i<sm;i++)
    {
        cin>>a[i]>>b[i]>>kk[i];
    }
    
    s=1;
    t=sn;
    nn=t+1;
    
    //这个精度问题还是很坑。。。
    double b=0,d=10000000.0;
    //好坑的东西! 我就操!
    int time=160;
    while(time--)//这里精度太小,竟然会死循环。。。
    {
        double mid=(b+d)/2;
        if( check(mid)==1 )
        {
            b = mid;
        }
        else
        {
            d = mid;
        }
    }
    printf("%.10lf",b*sx);
    return 0;
}

 

第二种精度处理方式:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <iostream>
using namespace std;
#define eps 1e-11
#define N 55
#define M 500500
#define INF 0x3fffff



struct node1
{
    long long to,w,next;
}edge[M];

long long sn,sm,sx;
long long pre[10*N];
long long g[N][N];
long long gap[10*N],lv[10*N];
long long k,c,m;
long long cnt;
long long n,nn;
long long s,t;
long long ans;
long long sum;


void add_edge(long long u,long long v,long long w)
{
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].next=pre[u];
    pre[u]=cnt++;
}

long long gdfs(long long k,long long w)
{
    if(k==t) return w;
    long long f=0;
    long long mi=nn-1;
    for(long long p=pre[k];p!=-1;p=edge[p].next)
    {
        long long v=edge[p].to,tw=edge[p].w;
        if(tw!=0)
        {
            if(lv[k]==lv[v]+1)
            {
                long long tmp=gdfs(v,min(tw,w-f));
                f+=tmp;
                edge[p].w-=tmp;
                edge[p^1].w+=tmp;
                if(f==w||lv[s]==nn) break;
            }
            if(lv[v]<mi) mi=lv[v];
        }
    }
    if(f==0)
    {
        gap[lv[k]]--;
        if( gap[ lv[k] ]==0 )
        {
            lv[s]=nn;
        }
        lv[k]=mi+1;
        gap[lv[k]]++;
    }
    return f;
}

long long sap()
{
    memset(lv,0,sizeof(lv));
    memset(gap,0,sizeof(gap));
    gap[0]=nn;
    while(lv[s]<nn)
    {
        sum+=gdfs(s,INF);
    }
    return sum;
}

long long a[505],b[505],kk[505];

long long check(long double mid)
{
    sum=0;
    mid/=sx;
    memset(pre,-1,sizeof(pre));
    cnt=0;
    
    for(long long i=0;i<sm;i++)
    {
        add_edge(a[i],b[i],(long long)(kk[i]/mid+eps));
        add_edge(b[i],a[i],0);
    }
    if(sap()>=sx)
    {
        return 1;
    }
    else return 0;
}



int main()
{
    cin>>sn>>sm>>sx;
    for(long long i=0;i<sm;i++)
    {
        cin>>a[i]>>b[i]>>kk[i];
    }
    
    s=1;
    t=sn;
    nn=t+1;
    
    //这个精度问题还是很坑。。。
    long double b=0,d=1000000000.0;
    //好坑的东西! 我就操!
    while(d-b > 1e-13)//这里精度太小,竟然会死循环。。。
    {
        long double mid=(b+d)/2;
        if( check(mid)==1 )
        {
            b = mid;
        }
        else
        {
            d = mid;
        }
    }
    printf("%.20Lf",b);
    return 0;
}

以上是关于CF1512D Corrupted Array 题解的主要内容,如果未能解决你的问题,请参考以下文章

CF360B - Levko and Array 题解

[CF722C] Destroying Array

codeforces CF718C Sasha and Array 线段树维护矩阵

Codeforces 刷题记录

cf C. Eugene and an array

CF1479B Painting the Array