zoukankan      html  css  js  c++  java
  • BZOJ4654 NOI2016国王饮水记(动态规划+三分)

      有很多比较显然的性质。首先每个城市(除1外)至多被连通一次,否则没有意义。其次将城市按水位从大到小排序后,用以连通的城市集合是一段前缀,并且不应存在比1城市还小的。然后如果确定了选取的城市集合,每次选择也应该是连续的一段,且应从小到大选,这样保证了将其他城市的水尽量分到1,而不是被另外的城市分流。同时也说明如果不考虑次数限制应该划分的尽量多。

      考虑怎么用这些性质做。按水位从小到大排序,考虑大力dp,即设f[i][j]为前i个城市(可以不全选)分了j组时的答案,转移即f[i][j]=max{(f[k][j-1]+si-sk)/(i-k+1)}。转移显然可以看做是找该点与其他点的斜率最大值,可以在下凸壳上三分。于是可以得到一个O(nkplogn)的优秀算法。

      感觉上这个高精度的保留位数实在有点唬人,哪来那么大误差啊?于是考虑直接用long double,记录转移点,最后再用高精度计算答案。直接从复杂度里去掉了一个p,效果拔群。获得了82分的好成绩,3T1WA。瞎猜了一发答案随分组数量变化是个凸函数,搞了个wqs二分上去,非常惨的假掉了。然后突然发现之前的82分代码算斜率甚至忘了return,加上之后获得了94分的好成绩,get了两个WA。再冷静一下发现之前因为空间不够把数组开小了,改成滚动之后又过掉最后一个点,获得了97分的好成绩。然后想起来没有把<h1的去掉因为感觉没有必要,去掉之后,就过了。

      就这么水过算了我不管了反正正解那种结论怎么猜的到啊。

    //以下代码删除了高精度类
    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include <string>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 8010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,p,a[N],b[N],from[N][N],q[N],h;
    long double f[2][N];
    Decimal calc(int m,int n)
    {
        if (m==0) return Decimal(h);
        return (calc(m-1,from[m][n])+a[n]-a[from[m][n]])/(n-from[m][n]+1);
    }
    long double slope(int j,int x,int y){return ((a[y]-f[j][y])-(a[x]-f[j][x]))/(y-x);}
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4654.in","r",stdin);
        freopen("bzoj4654.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),p=read();
        for (int i=1;i<=n;i++) a[i]=read();h=a[1];
        int t=0;for (int i=1;i<=n;i++) if (a[i]>h) b[++t]=a[i];
        sort(b+1,b+t+1);n=t;for (int i=1;i<=n;i++) a[i]=b[i];
        for (int i=1;i<=n;i++) a[i]+=a[i-1];
        for (int i=0;i<=n;i++) f[0][i]=h;
        for (int j=1;j<=min(n,m);j++)
        {
            int tail=0;memset(f[j&1],0,sizeof(f[j&1]));
            for (int i=1;i<=n;i++)
            {
                while (tail>1&&slope(j&1^1,q[tail-1],q[tail])>slope(j&1^1,q[tail],i-1)) tail--;
                q[++tail]=i-1;
                int l=1,r=tail;
                while (l+3<r)
                {
                    int mid1=(l+r>>1)-1,mid2=(l+r>>1)+1;
                    if ((f[j&1^1][q[mid1]]+a[i]-a[q[mid1]])*(i-q[mid2]+1)<(f[j&1^1][q[mid2]]+a[i]-a[q[mid2]])*(i-q[mid1]+1)) l=mid1;else r=mid2;
                }
                for (int k=l;k<=r;k++)
                if (f[j&1^1][q[k]]+a[i]-a[q[k]]>f[j&1][i]*(i-q[k]+1)) f[j&1][i]=(f[j&1^1][q[k]]+a[i]-a[q[k]])/(i-q[k]+1),from[j][i]=q[k];
            }
        }
        cout<<calc(min(n,m),n).to_string(p+1);
        return 0;
    }
  • 相关阅读:
    欣喜:终于找到了办法,可以把图片资源集成到dll文件之中了
    复习:关于类的继承和构造函数
    让Fckeditor支持中文——解决“Error loading "/fckeditor/fckstyles.xml" ”
    asp.net小技巧:保留password模式文本框textbox内的数据不丢失。
    数据库备份和恢复速记!
    资源:全球化与本地化(二)——指定语言语种
    一个Javascript类URI,顺便当作学习js类的笔记了。
    学习笔记:TimeSpan(时间片),以及各种时间差的算法
    ASP.NET MVC数据验证
    反射和属性
  • 原文地址:https://www.cnblogs.com/Gloid/p/10192444.html
Copyright © 2011-2022 走看看