zoukankan      html  css  js  c++  java
  • Codeforces Round#409/VK-Cup 2017 Round2

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    和ditoly组队打VK-Cup,起了个名字叫Vegetable Chicken(意思显然),然后昨天我做AB他切C

    很不幸的是.....我写的两题都挂了......坑队友了...A被疯狂卡精度  B简单计算几何瞎写挂了  GG 滚去外卡赛

    A.Voltage Keepsake

    你有n个东西,每个东西每秒钟消耗ai的能源,初始有bi的能源。你还有一个充电器,每秒钟可以充p的能源,问最多多久之后才有东西爆零。n<=100000

    直接二分呗。然后记得直接把$sum{ai}leqslant p$的直接判掉,不然被疯狂卡精度,longdouble过不去,但是float128可过(10倍常数左右)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define eps 1e-6
    #define MN 100000
    #define ll long long
    #define ld long double
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return f?x:-x;
    }
    
    int n;
    ld a[MN+5],b[MN+5],p,tot;
    
    int main()
    {
        n=read();p=read();
        for(int i=1;i<=n;i++)a[i]=read(),b[i]=read(),tot+=a[i];
        if(tot<=p)return 0*puts("-1");
        ld l=0,r=1e18,mid,sum=0;
        for(int j=1;j<=100;j++)
        {
            mid=(l+r)/2.0;sum=0;
            for(int i=1;i<=n;i++)
                sum+=max((ld)0,(a[i]*mid-b[i])/p);
            if(sum<mid+eps) l=mid;
            else r=mid;
        }
        if(r+eps>=(ld)1e17) return 0*puts("-1");
        printf("%0.6lf
    ",(double)(l+r)/2.0);
        return 0;
    }

    B. Volatile Kite
    给定一个凸多边形,求一个最大的D,每个点无论在距离D里面怎么移动,都还是凸多边形. n<=1000

    发现题目是求一个点到两点连线距离的最小值的一半,只要判相邻的三个点就行了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define eps 1e-8
    #define MN 1000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return f?x:-x;
    }
    inline double sqr(double x){return x*x;}
    struct P
    {
        double x,y;
        P(double _x=0,double _y=0):x(_x),y(_y){}
        double operator^(P b){return fabs(x*b.y-b.x*y);}
        P operator-(P b){return P(x-b.x,y-b.y);}
        friend double dis(P a,P b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
    }p[MN+5];
    
    int n;
    double ans=1e18;
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) p[i].x=read(),p[i].y=read();
        for(int i=1;i<n;i++) ans=min(ans,dis(p[i],p[i+1])/2.0);
        ans=min(ans,dis(p[n],p[1])/2.0);
        p[n+1]=p[1];p[n+2]=p[2];
        for(int i=1;i<=n;i++)
            ans=min(ans,((p[i]-p[i+1])^(p[i+2]-p[i+1]))/dis(p[i],p[i+2])/2);
        printf("%0.7lf
    ",ans);
        return 0;
    }

    C.给定n个0-m-1的数字和m,你要构造一个尽可能长的数列,满足前缀积互不相同,且n个数都没有出现。n<=m<=200000

    裴蜀定理,把每一个数字和m求gcd然后扔在一起,然后每个gcd都可以向它的倍数转移,dp求一个最长路径,最后用exgcd求一下方程系数输出就行了。

    #include<iostream>
    #include<cstdio>
    #include<vector> 
    #define MN 200000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int  n , m , from , ans = 0 , f[MN + 5] , last = 1 , ne[MN + 5];
    bool b[MN + 5];
    vector<int> v[MN + 5];
    inline int gcd(int x,int y){return !y ? x :gcd(y , x % y);}
    
    int exgcd(int a , int b , int&x , int&y)
    {
        if(!b) {x = 1 , y = 0; return a;}     
        int c = exgcd(b , a % b , x , y);
        int t = x; x = y; y = t - (a / b) * x;
        return c;
    }
    
    void solve(int x)
    {
        if(ne[x]) solve(ne[x]);
        int X = 0, Y = 0 , Z;
        for(int i = 0 ; i < v[x].size() ; ++i)
            Z = exgcd(last , m , X , Y) , printf("%d ",(1LL * X * v[x][i] / Z % m + m) % m) , last = v[x][i];
    }
    
    int main()
    {
        n = read(); m = read();
        for(int i = 1 ; i <= n ; ++i) b[read()] = 1;
        for(int i = 1 ; i < m ; ++i) if(!b[i]) v[gcd(i , m)].push_back(i);
        for(int i = 1 ; i < m ; ++i) 
        {
            if((f[i] += v[i].size()) > ans) ans = f[i] , from = i;
            for(int j = i << 1 ; j < m ; j += i)
                if(f[i] > f[j]) f[j] = f[i] , ne[j] = i;
        }
        printf("%d
    ", ans + !b[0]);
        solve(from);
        if(!b[0]) puts("0");
        return 0;
    }

    D.Varying Kibibits

    定义f(s1,s2...sn)的每一位是这n个数里面那一位的最小值  求

    就是对于每一个f(x)的值等于x的子序列si,计算它的和的平方的和乘以x.

    给定n个数,求G(1)^G(2)^...^G(n)  n<=10^6 数字在[0,10^6-1]

    题解:枚举x,如果直接算等于x的,显然不好做,考虑容斥原理,计算每一位都大等于x的每一位的答案。这样我们只要对于一个集合能够求出它的子集的和的平方和就行了。

    比如只有两个数字a,b 答案是$(a^{2}+b^{2})+(a+b)^{2}$

    如果有三个数字abc,答案是$2(a^{2}+b^{2}+c^{2})+2(a+b+c)^2$

    ......

    然后经过乱拆之后一番找规律,发现如果有k个数字,答案是2^(k-2)乘以它们的平方和加上和的平方,k比较小的时候特判一下。所以我们对于每一个数,维护大等于它的数字的 平方和 , 和 , 数字个数  就可以算出答案了。

    转移和计算答案都用容斥原理,2的次方可以预处理,复杂度$O(2^{6}*10^{6})$,自带大常数,我上fread卡了一会儿常数才过去。 

    代码有点丑

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define MN 1000000
    #define ll long long
    #define mod 1000000007
    char B[1<<26],*S=B;
    #define getchar() (*S++)
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return f?x:-x;
    }
    
    int n,num[MN+5],sq[MN+5],sum[MN+5],a[MN+5],C,D,pw[7],X,p[MN+5];
    ll res=0,ans;
    inline void R(int&x,int y){x+=y;(x>=mod)?x-=mod:0;x<0?x+=mod:0;}
    void dfs(int x,int now,int k,int l)
    {
        if(x>6)
        {
            if(l!=X&&num[l])
            {
                R(num[X],k*num[l]);
                R(sq[X],k*sq[l]);
                R(sum[X],k*sum[l]);
            }
            return;
        }
        int la=now%10;now/=10;
        dfs(x+1,now,k,l+la*pw[x]);
        if(la<9) dfs(x+1,now,-k,l+(la+1)*pw[x]);
    }
    
    inline int Sqr(int x){return 1LL*x*x%mod;}
    void solve(int x,int now,int k,int l)
    {
        if(x>6)
        {
            if(num[l])
            {
                if(k==-1) k=mod-1;
                if(num[l]==1) ans=(ans+1LL*k*Sqr(sum[l]))%mod;
                else
                {
                    int times=p[num[l]-2];
                    ans=(ans+1LL*k*times%mod*(1LL*Sqr(sum[l])+sq[l])%mod)%mod;
                }
            }
            return;
        }
        int la=now%10;now/=10;
        solve(x+1,now,k,l+la*pw[x]);
        if(la<9) solve(x+1,now,-k,l+(la+1)*pw[x]);
    }
    
    inline int U(int x){return x>=mod?x-=mod:x;}
    
    int main()
    {
        fread(B,1,1<<26,stdin);
        n=read();pw[1]=p[0]=1;
        for(int i=1;i<=1000000;i++) p[i]=U(p[i-1]<<1);
        for(int i=2;i<=6;i++)pw[i]=pw[i-1]*10;
        for(int i=1;i<=n;i++)
            ++num[a[i]=read()],sq[a[i]]=(sq[a[i]]+1LL*a[i]*a[i])%mod,(sum[a[i]]+=a[i])%=mod;
        for(X=999999;~X;--X) dfs(1,X,-1,0);
        for(X=999999;X;--X)
        {
            ans=0;solve(1,X,1,0);
            res=res^(1LL*ans*X);
        }
        cout<<res;
        return 0;
    }
  • 相关阅读:
    机器学习: t-Stochastic Neighbor Embedding 降维算法 (二)
    数学辨异 —— 泰勒展开与等比数列求和
    HDU 4705 Y
    C#实现的内存分页机制的一个实例
    java程序获得SqlServer数据表的表结构
    GLSL中的各种变量总结
    HTTP协议学习
    Jedis中的一致性hash
    C语言数据结构----双向链表
    ios7毛玻璃效果实现
  • 原文地址:https://www.cnblogs.com/FallDream/p/vkcup2017round2.html
Copyright © 2011-2022 走看看