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杯”中国大学生算法设计超级联赛题解的主要内容,如果未能解决你的问题,请参考以下文章