1. 程式人生 > >ACM/ICPC 2018亞洲區預選賽北京賽站網路賽 K-Dimensional Foil II(二分瞎搞)

ACM/ICPC 2018亞洲區預選賽北京賽站網路賽 K-Dimensional Foil II(二分瞎搞)

傳送門

這題其實沒有題面看起來複雜,實際上我們貪心的去想:對於下式

                                                                          S=\sum\limits_{i=1}^Na_i^2

如果我們有這麼一種操作可以把某個a_i減一,現在問一次操作後S的最小值,

那麼很容易便可以知道我們肯定是去找最大的那個去減一,最後的結果才會最小.

對於這道題其實也一樣,我們肯定也是選相對於圓心數值的差(加絕對值)大的維度優先去減小,這樣一直貪心下去,

最後落到上面的點肯定就是我們要求的點。

對於這樣一種操作,我們可以發現,在經過若干次操作後,這k個維度的向量的長度的最大的那幾個肯定數值是相等的,

這是由於我們貪心的選取最大的去減所導致的,由於我們每次減的數值很小,誤差小於題目中給的1e-4,那麼對於結果來說數值就是無誤的.

這樣一來,對於這麼些操作我們便可以用二分去替代,二分我們最後劃定的那個最大值的數值便可以解決此問題。

#include<bits/stdc++.h>
using namespace std;
double eps=1e-6;
double c[105],s[105];
double conv[105];
double ans[105];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k,r;
        scanf("%d%d",&n,&k);
        scanf("%d",&r);
        for(int i=1;i<=k;i++) scanf("%lf",&c[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=k;j++) scanf("%lf",&s[j]),conv[j]=abs(s[j]-c[j]);
            double L=0,R=1e8;
            while(L<R-eps)
            {
                double mid=(L+R)/2.0;
                double sum=0;
                for(int j=1;j<=k;j++) sum+=max(0.0,conv[j]-mid);
                if(sum<=r) R=mid;
                else L=mid;
            }
            for(int j=1;j<=k;j++)
            {
                if(conv[j]>=R) conv[j]=R;
                if(s[j]>c[j]) ans[j]=-conv[j]+s[j];
                else ans[j]=conv[j]+s[j];
                printf("%.5f ",ans[j]);
            }
            printf("\n");
        }
    }
}