zoukankan      html  css  js  c++  java
  • 启智树提高组day4T1 T1(t1.cpp,1s,512MB)

    启智树提高组day4T1 T1(t1.cpp,1s,512MB)    

    题面描述    

    度为2n 的实数序列A考虑下列问题:

    设S为序列中所有元素的和。你可以做下列操作n次:

    • 选择两个未被选中过的下标i和j,要求i≠j ;
    • 将 Ai变为不超过Ai的最整数,即将 Ai向下取整;
    • 将Aj变为不小于Aj的最小整数,即将Aj向上取整。

    要求操作完成之后,新的序列中所有元素之和S'和S的差的绝对值尽量小。

    现在给你度为m的实数序列B,有Q组询问。每组询问要求将这个序列的个区间作为上述问题中的A求解。

    输入格式

    ⼀⾏两个正整数m ,Q 。第⼆⾏ m个 0到 10^4之间的实数Ai ,每个实数都恰好保留了三位小数。

    然后Q,每两个正整数Li,Ri ,表此次需要求解的区间为[Li,Ri] ,保证。

    输出格式    

    Q,每⾏⼀个实数,保留三位小数,表此次询问中 和 的差的绝对值可能取到的最小值。

    样例输入

    样例输出

    样例解释

    数据范围

    解题思路

    我的基本想法

    输入这个数组,记录每个数字的小数部分;

    取出并复制其需要区间

    排序,但是要先去掉小数区间为0的,因为零的话既可以向上取整,也可以向下取整

    一个循环,循环区间中不为0 的数字的个数的一半。每次循环时取出一个最小值和最大值;

        但是如果这时,最小值>0.5的话就要考虑使用0来补位。最大值同理。

     1 while(li<=ri)
     2 
     3 {
     4 
     5 if(range[li]>0.5&&zero) li--,zero--;
     6 
     7 else{
     8 
     9 ans-=range[li];
    10 
    11 // cout<<"ans+="<<range[li]<<endl;
    12 
    13 }
    14 
    15 if(range[ri]<=0.5&&zero) ri++,zero--;
    16 
    17 else{
    18 
    19 ans+=1-range[ri];
    20 
    21 // cout<<"ans+=1-"<<range[ri]<<endl;
    22 
    23 }
    24 
    25 li++;
    26 
    27 ri--;
    28 
    29 }

    Code

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<iomanip>
     7 #include<map>
     8 #include<set>
     9 #include<queue>
    10 #include<vector>
    11 #define IL inline
    12 #define re register
    13 #define LL long long
    14 #define ULL unsigned long long
    15 using namespace std;
    16 
    17 template<class T>inline void read(T&x)
    18 {
    19     char ch=getchar();
    20     while(!isdigit(ch))ch=getchar();
    21     x=ch-'0';ch=getchar();
    22     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    23 }
    24 int G[55];
    25 template<class T>inline void write(T x)
    26 
    27 {
    28     int g=0;
    29     do{G[++g]=x%10;x/=10;}while(x);
    30     for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('
    ');
    31 }
    32 
    33 double a[500000],m[500000];
    34 int M,Q;
    35 vector<double>range;
    36 double ans;
    37 int main()
    38 {
    39     cin>>M>>Q;
    40     for(re int i=1;i<=M;i++) cin>>a[i],m[i]=a[i]-floor(a[i]);
    41     int l,r;
    42     while(Q--)
    43     {
    44         read(l),read(r);
    45         range.clear();
    46         ans=0;
    47         int zero=0;
    48         for(re int i=l;i<=r;i++) if(m[i]) range.push_back(m[i]); else zero++;
    49         sort(range.begin(),range.end());    
    50         re int li=0,ri=range.size()-1;
    51         while(li<=ri)
    52         {
    53             if(range[li]>0.5&&zero) li--,zero--; 
    54             else{
    55                 ans-=range[li];
    56 //                cout<<"ans+="<<range[li]<<endl;
    57             }
    58             if(range[ri]<=0.5&&zero) ri++,zero--;
    59             else{
    60                 ans+=1-range[ri];
    61 //                cout<<"ans+=1-"<<range[ri]<<endl;
    62             }
    63             li++;
    64             ri--;
    65         }
    66         
    67         cout<<fixed<<setprecision(3)<<fabs(ans)<<endl;
    68     }
    69     return 0;
    70 }
    暴力

    提交的时候,忘记去除调试信息……啊啊啊啊啊啊……

    当然,这是暴力,10分吧。

    正解

    观察暴力,可以发现,一段区间的S’只和实数和,下取整和,上取整和有关系

    所以我们只要给三种(实数,下取整小数,上取整小数)搞一个前缀和就好。

    Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 template<class T>inline void read(T&x)
     4 {
     5     char ch=getchar();
     6     while(!isdigit(ch))ch=getchar();
     7     x=ch-'0';ch=getchar();
     8     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
     9 }
    10 int G[55];
    11 template<class T>inline void write(T x)
    12 
    13 {
    14     int g=0;
    15     do{G[++g]=x%10;x/=10;}while(x);
    16     for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('
    ');
    17 }
    18 int N,q,c[1<<19];double t[1<<19],s[1<<19];
    19 int main(){
    20     scanf("%d%d",&N,&q);
    21     for(int i=1;i<=N;i++){
    22         double x;
    23         scanf("%lf",&x),s[i]=s[i-1]+x,t[i]=t[i-1]+ceil(x);
    24         c[i]=c[i-1]+(floor(x)!=ceil(x));
    25     }
    26     while(q--){
    27         int l,r;read(l),read(r);
    28         int n=r-l+1>>1,cnt=c[r]-c[l-1];
    29         double tot=s[r]-s[l-1],tt=t[r]-t[l-1];//取出这一部分的和 
    30         if(tt-min(cnt,n)>tot) tt-=min(cnt,n);
    31         else{
    32             int v=min({cnt,n,int(tt-tot+.5-1e-8)}),t=n-v;
    33             tt-=v;
    34             if(2*n-cnt<t) tt-=t-(2*n-cnt);
    35         }
    36         printf("%.3lf
    ",abs(tt-tot));
    37     }
    38     return 0;
    39 }

    小结

    提交时去除调试信息

  • 相关阅读:
    【笔记】二进制文件
    vs2015+64位win10系统ceres-solver编译
    python
    感受函数式编程-scala
    R语言diagram包画订单状态流图
    virtualbox下Centos6.5桥接模式上网配置方法
    配置对IIS上tabular的 HTTP 访问
    centos6.5下逻辑卷操作
    centos6.5下磁盘创建交换分区
    centos6.5下磁盘分区及挂载
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/13534224.html
Copyright © 2011-2022 走看看