Codeforces Round #320 (Div. 2) A B C D E

来源:互联网 发布:linux中vim如何退出 编辑:程序博客网 时间:2024/05/16 08:27

这场被精度坑成SB了,因为精度问题WA了C和E,C题加一个误差修正值就GG了...E题三分精度用次数控制,但是我写循环的时候还是while(l<=r)了...哎 好弱。

A 判断输入的数字转化为二进制有多少个1即可...

#include<bits/stdc++.h>using namespace std;#define ll long longint main(){    int n;    scanf("%d",&n);    int ans=0;    while(n)    {        int t=n%2;        ans+=t;        n=n/2;    }    printf("%d\n",ans);    return 0;}
B  贪心,每次找最大的数字,并且这个数字所在的列和行都没被使用过..因为当时感觉B题不会出太难,果断贪心写了就对了..

#include<bits/stdc++.h>using namespace std;#define ll long longint dp[2000][2000];int used[2000],ans[2000];int main(){    int n;    scanf("%d",&n);    memset(dp,0,sizeof(dp));    for(int i=2;i<=2*n;i++)    {        for(int j=1;j<=i-1;j++)        {            scanf("%d",&dp[i][j]);            dp[j][i]=dp[i][j];        }    }    memset(used,0,sizeof(used));    for(int i=0;i<n;i++)    {        int maxi=-1,ti=-1,tj=-1;        for(int j=1;j<=2*n;j++)        {            for(int k=1;k<=j-1;k++)            {                if(used[j]==0&&used[k]==0)                {                    if(dp[j][k]>maxi)                    {                        maxi=dp[j][k];                        ti=j;tj=k;                    }                }            }        }        used[ti]=used[tj]=1;        ans[ti]=tj;        ans[tj]=ti;    }    for(int i=1;i<2*n;i++)        printf("%d ",ans[i]);    printf("%d\n",ans[n*2]);    return 0;}

C ...乱搞的数学题...因为公式不是窝推导的,不说啥。.

#include<bits/stdc++.h>using namespace std;#define ll long longint main(){    int a,b;    scanf("%d %d",&a,&b);    if(a<b)    {        printf("-1\n");        return 0;    }    double sum=a+b+0.0;    double ans;    sum=sum/2.0;    ans=(int)(sum/b+0.0);//此处窝室友推荐加一个比较小的数字来修正,果断FST了,删除了这个修正值就过了,精度卡的真真日了狗    sum=sum/ans;    printf("%.10f\n",sum);    return 0;}


D 当时推导是个DP,发现有些不是当前最优解但是没有记录...果然FST了,赛后有大牛说最优解肯定只有一个数字乘了x...窝感觉应该只是与最大的数字二进制数字位数相同的a[i]可能是这样...但是这样会很麻烦,没有去实验...

预先处理出前缀或和,后缀或和,直接枚举 复杂度O(n)

#include<bits/stdc++.h>using namespace std;#define ll long long#define MAXN 200010ll l[MAXN],r[MAXN];ll a[MAXN];int main (){    int n,k,x;    scanf("%d %d %d",&n,&k,&x);    l[1]=r[n+1]=0;    for(int i=1;i<=n;i++)    {        scanf("%I64d",&a[i]);        l[i]=l[i-1]|a[i];    }    for(int i=n;i>=1;i--)        r[i]=r[i+1]|a[i];    ll ans=0;    for(int i=1;i<=n;i++)    {        ll tmp=a[i];        for(int j=1;j<=k;j++)            tmp*=x;        ans=max(ans,l[i-1]|r[i+1]|tmp);    }    printf("%I64d\n",ans);    return 0;}

E. 给定一个n的序列,找出一个x,使得所有的序列中的数字-x后,这个序列的最大子段和最小,最大子段和是绝对值的,一段和是负数,要负数取绝对值计算在内...

因为x很大或者很小肯定子段和绝对值很大,在ansx这点左右两边扩大最大子段和都在增加,那么函数图像就是一个三分搜索的图像...直接三分,然后dp再O(n)的复杂度内求的最大子段和...这个题用次数控制三分精度比较好...

#include<bits/stdc++.h>using namespace std;#define eps 1e-7#define ll long long#define M 220000int a[M],n;double f[M],ans;double cal(double x){    double ans1=0;    f[1]=a[1]-x;    for(int i=2;i<=n;i++)    {        if(f[i-1]<0)            f[i]=a[i]-x;        else            f[i]=f[i-1]+a[i]-x;        ans1=max(ans1,f[i]);    }    f[1]=(a[1]-x);    ans1=max(ans1,-f[1]);    for(int i=2;i<=n;i++)    {        if(f[i-1]>0)            f[i]=(a[i]-x);        else            f[i]=f[i-1]+(a[i]-x);        ans1=max(ans1,-f[i]);    }    return ans1;}void sf(double l,double  r){    double mid,midmid;    int tmp=0;    while(1)    {        mid=(l+r)/2;        midmid=(mid+r)/2;        double x=cal(mid);        double y=cal(midmid);        if(x<y)        {            ans=min(ans,x);            r=midmid;        }        else        {            ans=min(ans,y);            l=mid;        }        tmp++;        if(tmp>500)            break;    }}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    ans=10000000000;    sf(-100000,10000);    printf("%.9f\n",ans);    return 0;}



0 0
原创粉丝点击