2017多校第7场

先把会的写一下题解吧,以后慢慢补上。


HDU 6217-Hard challenge

题意:二维平面内有n个点,每个点都有坐标和一个val值,任意两点之间都有一条线段连接,线段的贡献值为两个端点的val之积,且不存在过两个点的直线也经过原点。求一条过原点的直线与线段相交所得的贡献值最大。

应该算简单的计算几何吧。先来看一个不等式:ab<=((a+b)^2)/2 当且仅当a=b时取等。根据题意,我们自然可以用一条直线将这些点划分为两个集合(这样就和过原点的直线相交了),答案即这两个集合的val之积。现在怎么将这些val分成两个集合并且差值最小呢,注意tot_val<=5e8。背包肯定是不行的,还是根据题意,经过原点的直线每扫到一个点必然会将所有的点分为两部分,我们只需维护两个集合的val值即可。这里用的是以y轴作为起始扫描线,顺时针按斜率从大到小扫描,起始就可以分为x>0和x<0两个集合,然后特判在y轴上的点属于哪边会有最优解,接下来开始扫描,对了,得先按斜率从大到小排个序。每扫到一个点就把这个点原属的val集合减去,另一个val集合加上,然后遍历所有点取最优解即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps=1e-8;
const int N=5e4+10;
struct point//定义点
{
    double x,y;
    ll val;
} p[N] ;
struct line//线
{
    point a,b;
};
int cmp(point a,point b)
{
    return (a.y/a.x)>(b.y/b.x);
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        int k=0;
        scanf("%d",&n);
        ll val,sum1=0,sum2=0,ans=0,tmp1=0,tmp2=0;
        double x,y;
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf%lld",&x,&y,&val);
            if(x==0)
            {
                if(y>0)  tmp1+=val;//y轴上的点,有且仅有一个
                else  tmp2+=val;
            }
            else p[k].x=x,p[k].y=y,p[k++].val=val;
        }
        sort(p,p+k,cmp);
        for(int i=0; i<k; i++)
        {
            if(p[i].x>0) sum2+=p[i].val;
            else sum1+=p[i].val;
        }
        ans=max((sum1+tmp1)*(sum2+tmp2),(sum2+tmp1)*(sum1+tmp2));
        sum1+=tmp1,sum2+=tmp2;
        for(int i=0; i<k; i++)
        {
            if(p[i].x>0)
            {
                ans=max(ans,(sum1+p[i].val)*(sum2-p[i].val));
                sum1+=p[i].val;
                sum2-=p[i].val;
            }
            else
            {
                ans=max(ans,(sum1-p[i].val)*(sum2+p[i].val));
                sum1-=p[i].val;
                sum2+=p[i].val;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}


HDU-6129 Just do it

这道题结束看大牛的题解才发现有惊喜,挺不错的一道题,奈何蒟蒻在做比赛时没有做出来,今早推了一下就补出来 了。。

题意:给你一个n个数的序列,每次构造一个前缀异或和序列。求构造m次之后的序列。

比赛最开始看的一道题,结果到最后还是没做出来。上手以为这类题的套路大概是暴力找循环节,于是手推了n较小的情况,发现都符合,但为了保险于是打个表,却发现n越大其循环节呈log增长,这样就没什么想法了。队友在写其他4个题的时候自己手写了前几个数的构造规律,发现dp[i][j]=dp[i-1][j]^dp[i][j-1]。但还是没想法,队友把其他4道比较水的题都做出来之后我暴力写了一发,当然是T了, 于是坐等(以)题(待)解(毙)。关键在于上述转移方程式可以推出:dp[i][j]=dp[i-2^k][j]^dp[i][j-2^k]。知道了这个就很好写了,但二维数组肯定开不下,其实一维的就完全可以了。k=0、1、2、3...的时候,我们就一直在构造当m较小的情况,构造到第m个序列的时候自然已经知道了前面所有的序列了。而任意数m也都是由0+1+2+4+....这样构造的,所以m一直减去其lowbit(m),这里就可以优化到一维了,注意i-lowbit(m)>=0,那么a[i]=a[i]^a[i-lowbit(m)]。

const int N=1e5+10;
int lowbit(int x)
{
    return x&(-x);
}
int a[N*2];
int main()
{
    int t,n,m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        a[0]=0;
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        while(m)
        {
            int x=lowbit(m);
            for(int i=1; i<=n; i++)
                if(i-x>=0)
                    a[i]^=a[i-x];
            m-=x;
        }
        for(int i=1; i<=n; i++)
            printf("%d%c",a[i],i==n?'\n':' ');
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值