2021“MINIEYE杯”中国大学生算法设计超级联赛题解

Posted 满天星!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021“MINIEYE杯”中国大学生算法设计超级联赛题解相关的知识,希望对你有一定的参考价值。

2021“MINIEYE杯”中国大学生算法设计超级联赛(3)题解

6976 Game on Plane

题意:

有 n条直线,Alice每次选1,2,…,n条直线,Bob每次画一条直线,答案是Bob画的直线和Alice选的直线的相交数,现在Alice想要最大化答案,Bob想要最小化答案,问每次选1,2,…,n条直线的答案是多少.

思路:
首先能想到的是Alice肯定要选彼此不平行的直线,Bob肯定要选平行最多的直线画一条和它们斜率相同的直线,那么也就不难想到Alice的选法最优策略就是最小化斜率出现次数的最大值,所以不断从每种斜率的直线中各选一种,一定是在各个斜率循环跑,具体实现过程就是将各个斜率按直线数排序,从最大的开始跑即可。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>p;
p a[100010];
int i,j,k;
int f[100010];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
    int t;
    scanf("%d",&t);
    int dx,dy;
    int x1,x2,y1,y2;
    while(t--){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            dx=x1-x2;dy=y1-y2;
            if(dx==0) dy=1;   //如果垂直于坐标轴x y=1;
            else if(dy==0) dx=1;  //如果垂直于坐标轴y x=1;
            else{
                if(dx<0) {dx*=-1;dy*=-1;}  //因为要用x排序,则xy正负同时颠倒,保证了斜率不变 但又可以排序
                int d=gcd(abs(dx),abs(dy));
                dx/=d;dy/=d; }
            a[i]=p(dx,dy); }   //用pair存"斜率"(直接存坐标防止误差)
        sort(a+1,a+1+n);     //根据从小到大排序
        for(i=1;i<=n;i++) f[i]=0;  //初始化记录斜率相同数量的组数
        for(i=1;i<=n;i=j)
        {  //j-i描述斜率相同直线数量
            for(j=i;j<=n&&a[i]==a[j];j++);   //记录了当前斜率相同的有几个
            for(k=1;k<=j-i;k++) f[k]++;    //记录了斜率分布的个数,保存至数组中
        }
        for(i=j=1;i<=n;i++){
            while(f[j]==0) j++;   //j为最多可以平行的边数
            f[j]--;  //--意味该线被选取
            cout<<i-j<<endl;  //j来描述当前相同斜率最多的条数
        }
    } return 0;
}

6979 Photoshop Layers

题意:
给你n个用16进制表示的RGB三元组,q个询问,询问区间[l,r]的三元组和,如果某个三个元组的状态为1,那么直接用该三元组的值覆盖前面的值,如果是2则正常求和.

思路:
可以看出,只要所查询的区间中出现了1模式的图层,那么该区间就可以转换为这一点和右端点之间的查询,最后就可以转换成某一段由1个“1”模式和n个“2”模式相加的情况。
我们在构造初始数组的时候直接也就按照这个规律来构造即可。

6983 Segment Tree with Pruning

题意:
对区间[1,n]建线段树,返回条件是r−l+1<=k,问建成的线段树有多少节点?

思路:
可以直接模拟建树过程,对区间长度记忆化搜索,因为区间长度相同,其子节点个数也都是相同的.

AC代码1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll n,k;
map<ll,ll>T;
ll build(ll n)
{
    if(T.find(n)!=T.end()) return T[n];
    if(n<=k) return T[n]=1;
    else return T[n]=build(n/2)+build(n-n/2)+1;  //建左右子树
}
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        T.clear();
        cout<<build(n)<<endl;
    }return 0;
}

AC代码2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,ll>mp;
ll n,k;
ll build(ll l,ll r){
    if(mp.count(r-l))return mp[r-l];
    if(r-l+1<=k) return 1;
    ll mid=(l+r)/2,sum=1;
    sum+=build(l,mid);
    sum+=build(mid+1,r);
    return mp[r-l]=sum;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        mp.clear();
        cin>>n>>k;
        cout<<build(1,n)<<endl;
    }return 0;
}

如果觉得写的还不错,点个赞吧^ - ^

以上是关于2021“MINIEYE杯”中国大学生算法设计超级联赛题解的主要内容,如果未能解决你的问题,请参考以下文章

2021“MINIEYE杯”中国大学生算法设计超级联赛补题

2021“MINIEYE杯”中国大学生算法设计超级联赛题解

2021杭电多校赛2021“MINIEYE杯”中国大学生算法设计超级联赛签到题3题

2021“MINIEYE杯”中国大学生算法设计超级联赛

2021“MINIEYE杯”中国大学生算法设计超级联赛题解

6983 杭电多校(2021“MINIEYE杯”中国大学生算法设计超级联赛3) [记忆化搜索]