HDU 6127 Hard challenge+HDU 6129 Just do it【2017多校联赛】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Jane_JXR/article/details/77206908

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6127


官方题解:平面直角坐标系上有n个整点,第i个点有一个点权val_i,坐标为(x​i​,y​i​​),其中不存在任意两点连成的直线经过原点。这些整点两两之间连有一条线段,线段的权值为其两端点的权值之积。你需要作一条过原点而不过任意一个给定整点的直线,使得和这条直线相交的线段的权值和最大。

对于一条直线,线段权值和实际上就等于其两边点权和的乘积,所以把所有点按极角排个序,然后扫一圈就好了。


分析:对所有的点先极角排序,以Y轴为分界线开始扫描,分别计算直线左右两边的价值和,则score=lsum*rsum,然后对点扫描(其实就是按顺时针方向旋转得到新的直线),更新lsum,rsum(根据具体的图来更新,lsum+,rsum-/sum+,lsum-),更新最大score。【注意数据范围】

CODE:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<math.h>
#include<map>
#include<iostream>
#define INF 0x3f3f3f3f
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
#define PI acos(-1.0)
typedef  long long LL;
using namespace std;
const int mod=998244353;
const int maxn=3000005;
struct node
{
    double x,y,k;
    LL val;
    bool operator < (const node &cmp)const
    {
        return k<cmp.k;
    }
}c[maxn];
int main()
{
   int t,n;
   scanf("%d",&t);
   while(t--)
   {
       scanf("%d",&n);
       for(int i=1;i<=n;i++)
       {
           scanf("%lf%lf%lld",&c[i].x,&c[i].y,&c[i].val);
           if(c[i].x==0)
            c[i].k=PI/2;
           else
            c[i].k=atan(c[i].y/c[i].x);
       }
       sort(c+1,c+1+n);
       LL lsum=0,rsum=0;
       for(int i=1;i<=n;i++)
       {
           if(c[i].x>=0)
            lsum+=c[i].val;
           else
            rsum+=c[i].val;
       }
       LL ans=lsum*rsum;
       for(int i=1;i<=n;i++)
       {
           if(c[i].x>=0)
            lsum-=c[i].val,rsum+=c[i].val;
           else
            rsum-=c[i].val,lsum+=c[i].val;
            ans=max(ans,lsum*rsum);
       }
       printf("%lld\n",ans);
   }
   return 0;
}

HDU 6129 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6129

官方题解:有一个长度为nn的整数序列{a_n}{an},对其做mm次前缀异或和,求最终的序列。

可以发现做m次后,位置为x的初始值对位置为y的最终值的贡献次数是一个只和m与y-x相关的组合式,而我们只关注这个次数的奇偶性。考虑Lucas定理,C(a,b)是奇数当且仅当把a,b二进制表达后b中1的位置是a中1的位置的子集,于是这里所有满足条件的b有很好的性质,对每一个二进制位独立处理就能算出答案。


分析:打表找规律(看b[i]是由前面多少个数异或而来,两个相同数异或为0,我们只需要记录奇偶,看最终结果跟谁有关即可)

          1                2                3                    4                     5
1        (1)           (1,1)         (1,1,1)          (1,1,1,1)           (1,1,1,1,1)
2        (1)           (2,1)         (3,2,1)          (4,3,2,1)           (5,4,3,2,1)
3        (1)           (3,1)         (6,3,1)          (10,6,3,1)         (15,10,6,3,1)
4        (1)           (4,1)         (10,4,1)         (20,10,4,1)       (35,20,10,4,1)
5        (1)           (5,1)         (15,5,1)         (35,15,5,1)       (70,35,15,5,1)
dp[i][j]=dp[i-1][j]+dp[i][j-1];
我们可以发现一个神奇的规律:
m次操作之后,b[0]=a[0];
             b[1]=((C(m,1)%2)*a[0])^(a[1]);
             b[2]=((C(m+1,2)%2)*a[0])^((C(m,1)%2)*a[1])^(a[2]);
             b[3]=((C(m+2,3)%2)*a[0])^((C(m+1,2)%2)*a[1])^((C(m,1)%2)*a[2])^(a[3]);
             b[4]=((C(m+3,4)%2)*a[0])^((C(m+2,3)%2)*a[1])^((C(m+1,2)%2)*a[2])^((C(m,1)%2)*a[3])^(a[4]);
对于样例:3    3
1         2         3
0         1         1
                   a[1]
        a[1]     a[2]
a[1]  a[2]     a[3]
则:b[1]=a[1]
       b[2]=a[1]^a[2];
       b[3]=a[2]^a[3];

CODE:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<math.h>
#include<map>
#include<iostream>
#define INF 0x3f3f3f3f
typedef  long long LL;
using namespace std;
const int maxn=2*1e5+10;
int a[maxn];
LL exp_mod(LL a,LL b,LL p)
{
    LL res=1;
    while(b!=0)
    {
        if(b&1)
            res=(res*a)%p;
        a=(a*a)%p;
        b>>=1;
    }
    return res;
}
LL Comb(LL a,LL b,LL p)
{
    if(b==0||b==a)
        return 1;
    if(a<b)
        return 0;
    if(a==b)
        return 1;
    if(b>a-b)
        b=a-b;
    LL ans=1,ca=1,cb=1;
    for(LL i=0; i<b; ++i)
    {
        ca=(ca*(a-i))%p;
        cb=(cb*(b-i))%p;
    }
    ans=(ca*exp_mod(cb,p-2,p))%p;
}
LL Lucas(LL n,LL m,LL p)
{
    LL ans=1;
    while(n&&m&&ans)
    {
        ans=(ans*Comb(n%p,m%p,p))%p;
        n/=p;
        m/=p;
    }
    return ans;
}
LL b[maxn];
LL f[25];
void init()
{
    f[0]=1;
    for(int i=1; i<20; i++)
        f[i]=f[i-1]*2;
}
int gg[maxn];
LL sum[maxn];
int main()
{
    int t,n;
    init();
    LL m;
    scanf("%d",&t);
    while(t--)
    {
        memset(sum,0,sizeof(sum));
        memset(gg,0,sizeof(gg));
        scanf("%d%lld",&n,&m);
//        int pos=lower_bound(f,f+20,n)-f;
//        m%=f[pos];
//        cout<<f[pos]<<"----"<<f[pos+1]<<endl;
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        LL ans=0;
        for(int i=0; i<n; i++)
        {
            LL kk=Lucas(m+i-1,i,2);
//            cout<<kk<<"* ";
            if(kk)//看当前这位对结果的影响,如果为0,没任何影响
            {//如果为1,则后面所有的数都要依次对0~n-1-i异或
                for(int j=i; j<n; j++)
                {
                    sum[j]^=a[j-i];
                }
                //cout<<sum[i]<<" ";
            }
        }
        for(int i=0;i<n;i++)
        {
            if(i)
                printf(" ");
            printf("%lld",sum[i]);
        }
        printf("\n");
    }
    return 0;
}
还有一个神奇的做法,看上去很简单,不过不好想,目前还不太明白。

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;
}



n

猜你喜欢

转载自blog.csdn.net/Jane_JXR/article/details/77206908