2021杭电多校第三场

本文介绍了杭电多校算法竞赛中的四道题目,涉及线性数据结构的斜率优化、图层叠加求和、价格涨幅计算和区间查询优化。对于1004GameonPlane问题,通过最小化斜率出现次数的最大值实现最优策略;1007PhotoshopLayers通过前缀和技巧快速求解颜色叠加;1009RiseinPrice题目细节未给出;1011SegmentTreewithPruning利用奇偶性简化问题,高效输出答案。
摘要由CSDN通过智能技术生成

题目链接

题目链接

1004 Game on Plane

思路

这道题也是在看题解之后才写出来的,当时想到斜率这一方面了,但是还是没有理解清题意,所以没有明确的思路。Alice 为了让 Bob 与尽量多的直线相交,最优策略就是最小化斜率出现次数的最大值,所以不断从每种斜率的直线中各选一种即可。

附上代码

#include <bits/stdc++.h>
#include <iostream>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 200005
#define pi 3.141592653589793238462643383279
#define eps 1e-7

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double type;
typedef pair<int,int>P;

const int N=100005;
int t,n,i,j,k,f[N];
P a[N];
int gcd(int a,int b)//求最大公因数
{
    return b?gcd(b,a%b):a;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1; i<=n; i++)
        {
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            int dx=x2-x1,dy=y2-y1;
            if(dx==0)dy=1;
            else if(dy==0)dx=1;
            else
            {
                if(dx<0)dx=-dx,dy=-dy;
                int d=gcd(abs(dx),abs(dy));
                dx/=d,dy/=d;
            }
            a[i]=P(dx,dy);//将直线的斜率传到a数组中
        }
        sort(a+1,a+n+1);//进行排序
        for(i=1; i<=n; i++)
            f[i]=0;
        for(i=1; i<=n; i=j)
        {
            for(j=i; j<=n&&a[i]==a[j]; j++);//相当于计算从i开始有几条斜率相同的直线
            for(k=1; k<=j-i; k++)f[k]++;//将结果保存至f数组中
        }
        for(i=j=1; i<=n; i++)
        {
            while(!f[j])j++;
            f[j]--;
            printf("%d\n",i-j);//根据f数组得出结果
        }
    }
    return 0;
}

1007 Photoshop Layers

思路

这道题仔细分析可以发现就是一道求和的题目,给定n个图层,每个图层分为两种模式,模式1的话就是用当前的图层直接覆盖之前的图层,而模式2的话就是在原来的图层基础上加上当前的图层。
直接暴力解决一定会超时,所以要分析其中的规律,可以看出,只要所查询的区间中出现了1模式的图层,那么该区间就可以转换为这一点和右端点之间的查询,最后就可以转换成某一段由1个“1”模式和n个“2”模式相加的情况。
我们在构造初始数组的时候直接也就按照这个规律来构造即可。

附上代码

#include <bits/stdc++.h>
#include <iostream>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 200005
#define pi 3.141592653589793238462643383279
#define eps 1e-7

using namespace std;
typedef long long ll;
typedef double type;
int biao[lmax];//标记模式
int color1[lmax];//颜色的三个部分即R,G,B
int color2[lmax];
int color3[lmax];
int jilu[lmax];//记录模式为“1”的位置

int main()
{
    int t,n,q,l,r;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&q);
        int xi=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d %x",&biao[i],&color1[i]);
            color3[i]=color1[i]%256;//直接将每一部分的值赋给这一部分的数组
            color1[i]=color1[i]/256;
            color2[i]=color1[i]%256;
            color1[i]=color1[i]/256;
            if(biao[i]==1)
            {
                jilu[xi]=i;
                xi++;
            }
            else
            {
                color1[i]+=color1[i-1];//记录由“1”模式开始的这一段的前缀和
                color2[i]+=color2[i-1];
                color3[i]+=color3[i-1];
            }
        }
        for(int k=1; k<=q; k++)
        {
            scanf("%d%d",&l,&r);
            int i=l;//用i表示左端点,r还表示右端点
            int bb=upper_bound(jilu,jilu+xi,r)-jilu;//找到左端点的位置
            if(biao[r]==1)
            {
                i=r;
            }
            else
            {
                if(jilu[bb-1]>=l)
                    i=jilu[bb-2];
                else
                    i=l;
            }
            if(biao[i]==1)
                printf("%02X%02X%02X\n",min(color1[r],255),min(color2[r],255),min(color3[r],255));
            else
                printf("%02X%02X%02X\n",min(color1[r]-color1[i-1],255),min(color2[r]-color2[i-1],255),min(color3[r]-color3[i-1],255));
        }
    }
    return 0;
}

/*
3 2
3 1 2
4 2
4 1 3 2
*/

1009 Rise in Price

待补

1011 Segment Tree with Pruning

思路

这道题是队友写的,我听了一下思路,基本就是围绕奇偶性来寻找规律,然后将得到的答案输出。

附上代码

#include <bits/stdc++.h>
#include <iostream>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 200005
#define pi 3.141592653589793238462643383279
#define eps 1e-7

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double type;

ull qpow(long long a, int n)
{
    ull ans = 1;
    while(n)
    {
        if(n&1)
        {
            ans *= a;
        }
        a *= a;
        n >>= 1;
    }
    return ans;
}
int main()
{
    cin.sync_with_stdio(0);
    cin.tie(0);

    int t;
    cin >> t;
    ull res;
    while(t--)
    {
        res = 0;
        ull k, n;
        cin >> k >> n;
        if(n == 1)
        {
            cout << 2 * k - 1 << endl;
            continue;
        }
        ull c;
        c = k / n;
        int lay = log2(c);
        res += (qpow(2,lay + 1)-1);
        if((c = k / qpow(2, lay)) > n)
        {
            res += qpow(2, lay) * 2;
        }
        else if((c = k / qpow(2, lay)) == n)
        {
            res += 2 * (k % qpow(2, lay));
        }
        cout << res << endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值