A题
题意
给定一个正整数集合,判断能否在该集合中添加一个改前不存在的元素,使得加入的元素成为所有原集合元素的最近值(绝对值最小)。
思路
通过模拟,我们可以发现:符合题目条件的集合有以下几个特征:
元素数量为1,恒满足
元素数量为2,需要两个元素之间的abs(差值)大于1,满足,否则不满足
元素数量>2,恒不满足
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
void solve()
{
int n;
cin>>n;
set<LL> has;
for(int i=1;i<=n;i++)
{
LL x;
cin>>x;
has.insert(x);
}
if(has.size()<=1)cout<<"YES"<<endl;
else if(has.size()==2)
{
LL num[5];
int i=0;
for(auto x:has)
{
num[i++]=x;
}
if(abs(num[0]-num[1])<=1)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
B题
题意
有一条正方形方格连成的链,每个方格之间有一扇门可以选择锁或不锁,然后分别给出a和b可以出现的方格区间,求最少要锁住多少扇门能够使得无论a和b在各自区间内如何出现,都不能通过未锁的门相互到达(注:a和b初始不会出现在同一个方格内)
思路
得到的区间关系主要如下:
区间不相交:中间堵一扇门就行
区间相交:先把相交区间所涉及的每一扇门关掉,然后考虑边界问题:左右端点重复时,该端点不需要堵外侧的一扇门
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
void solve()
{
LL l,r;
LL L,R;
cin>>l>>r;
cin>>L>>R;
LL ll=min(l,L);//得到覆盖的方格区间
LL rr=max(R,r);
if(r<L||R<l)//如果区间没有相交,就只需要中间堵1扇门就行
{
cout<<"1"<<endl;
}
else
{
LL xl=max(l,L);//得到相交的区间
LL xr=min(R,r);
LL need=xr-xl+1+1;//这里加2是因为假设边界需要(比如a的最右边的格子在b的区间中间)
if(l==L)need--;//边界的不需要再堵门,因为a和b不会同时出现在一个格子里
if(R==r)need--;
cout<<need<<endl;
}
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C题
题意
有一堆给定价值的物品,A先手,A和B轮流取一份物品加到自己的价值里面,直到物品取完;A的目标是使得价值A-价值B的值最大,B的目标是使得价值A-价值B的值最小(换句话说:每个人都想要自己取得的物品的总价值最大);现在B可以提前进行以下操作:B有k个价值,能够将这些价值加到某些物品中,使得该物品的价值增加,从而实现自己的目标;现在求B经过最佳操作后能获得的A-B的值的最小值。
思路
读题时要注意:是总共能加k个价值,而不是每个物品最多加k价值(赛时太唐了,wa2了好几发)
既然是要最大化自己的价值,那肯定是贪心选价值最大的物品,那么我们可以将物品按照价值降序排序,偶数下标是A的物品,奇数下标是B的物品,B的价值肯定不能加到A的物品上,所以只能加到奇数位上,但是不能加太多,加太多就会破坏原有的顺序导致B的价值加到移位后的偶数位上,这个时候需要更多的额外价值抵消A增加的价值;所以加到与上一位相等就可以停止了。
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
LL num[N];
//千万不要用puts()和gets(),求求你了
bool cmd(LL a,LL b)
{
return a>b;
}
void solve()
{
LL n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>num[i];
}
sort(num+1,num+1+n,cmd);
LL A=0,B=0;
LL res=0;
for(int i=1;i<=n;i++)
{
//cout<<num[i]<<" ";
if(i%2==1)
{
res+=num[i];
}
else
{
LL need=num[i-1]-num[i];
need=min(k,need);
k-=need;
num[i]+=need;
res-=num[i];
}
}
//cout<<endl;
//cout<<A<<" "<<B<<endl;
cout<<res<<endl;
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
D题
题意
有编号从1~n的n个城市,每个城市有2种不同颜色传送门(一共只有4种传送门),然后有至少有一个相同颜色传送门的城市i,j之间可以相互通行,消耗为|i-j|,给定q个询问,询问从城市a到城市b最少的消耗是多少?
思路
可以证明:如果两个城市a和b可以直接相互通行,消耗肯定比其他方案要少;如果不能相互通行,则引进一个传送门组合和起点终点组合不同的城市z作为中转站,就可以通行:
a<z<b:res=b-a+1;
z<a<b:res=(b+a)-2*z
a<b<z:res=2*z-(b+a)
取最小值,
这里直接找编号离b最近的城市
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
map<string,int> op;
set<int> has[10];
map<int,string> type;
int n,q;
LL found_near(vector<int> num,int a,int b)
{
//mid<=l
int ans=1e9;
if(a>b)swap(a,b);
int l=0,r=num.size()-1;
while(l<r)
{
int mid=(l+r)/2;
if(num[mid]>=b)r=mid;
else l=mid+1;
}
//ans=min(ans,abs(num[l]-a)+abs(num[l]-b));
//mid>=r
if(num[l]>=b) ans=min(ans,2*num[l]-a-b);
if(num[l]<b&&l!=0)ans=min(ans,abs(num[l-1]-a)+abs(num[l-1]-b));
return ans;
}
void solve()
{
cin>>n>>q;
for(int i=1;i<=6;i++)has[i].clear();
type.clear();
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
has[op[s]].insert(i);//每种城市的编号
type[i]=s;//城市i的传送门类型
}
//for(int i=1;i<=6;i++)sort(has[i].begin(),has[i].end());
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
string op1=type[l];
string op2=type[r];
int type1=op[op1];
int type2=op[op2];
bool flag=false;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
if(op1[i]==op2[j])flag=true;//如果能够直接通行,优先直接通行
}
}
if(flag)
{
cout<<abs(l-r)<<endl;
continue;
}
else
{
int res=1e9;
if(l>r)swap(l,r);//否则,找到l,r之间的一个不同类型城市或者离r或l最近的城市
for(int i=1;i<=6;i++)
{
if(i==type1||i==type2)continue;//需要和起点终点城市类型不同
if(has[i].size()==0)continue;
auto ans=has[i].lower_bound(r);//手写二分有些问题,TLE了
if(ans!=has[i].end()) {res=min(res,(*ans)*2-l-r);}//找到离y编号最近的城市
if(ans!=has[i].begin()) {ans--;res=min(res,abs(*ans-l)+abs(*ans-r));}
}
if(res!=1e9)cout<<res<<endl;
else cout<<"-1"<<endl;
}
}
}
int main()
{
int t=1;
cin>>t;
op["BG"]=1;
op["BR"]=2;
op["BY"]=3;
op["GR"]=4;
op["GY"]=5;
op["RY"]=6;
while(t--)
{
solve();
}
return 0;
}