藏匿的刺客
藏匿的刺客
用时 1min 得分100
因为我发现这个其实就是区间选点,果然acwing很不错
代码就不提交了
幸运的店家
幸运的店家
看了题解,但是不太明白,似懂非懂的
/*
问题描述
炫炫开了一家商店,卖的货只有一个,XXX,XXX卖N元钱。
有趣的是,世界上只有面值为3的幂的纸币,即纸币只有1元的、3元的、9元的。。。。,
有一天,桥神来买XXX,可他没办法正好给出N元钱,而炫炫没法找零,于是他只好用他的钱凑出了一个比N大,
并且最小的价值,交给了炫炫。炫炫想知道,他这次最多可以得到多少张纸币。
输入格式
一个数,N
输出格式
一个数,为答案
样例输入
4
样例输出
2
数据规模和约定
n<=10^17
*/
/*
答案必不使用1,若需要使用若干1元,得到x,满足x > N。
那么去掉1元,得到x1,可能满足x1 >= N,当x1 > N,可知x不是最小,当x1 = N,不符合题意。
*/
#include<iostream>
using namespace std;
long long n;
int main(){
cin>>n;
if(n<=3){
//如果价格为1,2,3.如果凑不成恰好的,则都需要一枚货币(分别为3,3,9元)
cout<<1<<endl;
}
//如果价格不能被3整除,那么必然需要n/3+1个,就是全用3
//如果可以被3整除
/*
之前我是想尽可能使用3,到最后使用一个6但是
9-->3+3+6
这样的话直接可以3+6,不满足题意
那么这样的用3的n次幂组成
若N能被3整除,则答案是n / 3 + 1(将N的所有3因子除掉后得到n,即n满足 3^k * n = N )
如果不把 所有3因子 都除掉,那么最终总会可以凑出整钱
*/
else{
//对于3的倍数,要确保 “可他没办法正好给出N元钱”
//6:一张3,一张6 9:两张3,一张6 规律应该是x/3即张数
if(n%3==0){
while (n%3==0) n/=3;
cout<<n/3+1<<endl;
}
else{
cout<<n/3+1<<endl;
}
}
return 0;
}
区间分组
区间分组
方法一和二
方法一是我写的,应该是对的,不过最后超时了,确实时间复杂度太高
方法二是Acwing的方法,很巧妙地用了小顶堆
小顶堆的构造代码为priority_queue<int, vector<int>, greater<int>> heap;//构造一个小顶堆,greater表示顶堆元素最小
这个priority_queue
其实是优先队列,如果构造大顶堆就是priority_queue<int, vector<int>, less<int>> heap
本题贪心不难想,不能用右端点排序的数据为
[1,3][2,5][4,100][10,13]
代码
/*
给定 N 个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,
并使得组数尽可能小。
输出最小组数。
输入格式
第一行包含整数 N,表示区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示最小组数。
数据范围
1≤N≤10^5,
-10^9≤ai≤bi≤10^9
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
*/
//试了几个,感觉左右端点都行,因为我想要某个离当前区间最近的左端点,因此这次左端点升序,如果左一样,则右升序
#include<iostream>
#include<algorithm>
#include<list>
#include<vector>
#include <queue>
using namespace std;
const int N=1e5+10;
struct node{
int a,b;//左右端点
int e=0;
};
node q[N];
bool cmp(node x,node y){
if(x.a==y.a)
return x.b<y.b;
return x.a<y.a;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>q[i].a>>q[i].b;
int ans=0;
int sorted=0;
node m;
node ini;
ini.a=0;ini.b=0;
sort(q+1,q+1+n,cmp);
//利用这个算法会超时
//e是判断是否进组了,后续改代码的时候我就没删除它
/*
while(sorted!=n){
ans++;
//当所有区间都分组了才退出循环
for(int i=1;i<=n;i++){
if(q[i].e==0){
m=q[i];//每次开头都会选择一个区间作为新的组的第一个元素
q[i].e=1;//说明该区间已经排序了
sorted++;
break;
}
}
int i=1;
while(i<=n){
if(q[i].e==0&&q[i].a>m.b){
//如果某个区间没有用过且不相交,并且由于按照左端点排序了,因此是当前最优的区间
m=q[i];
q[i].e=1;
sorted++;
}
i++;
}
}
*/
//下面是Acwing做法
priority_queue<int, vector<int>, greater<int>> heap;//构造一个小顶堆,greater表示顶堆元素最小
//堆内某个元素是某个分组内最大的右端点
//用一个元素代表区间的那个分组
for(int i=1;i<=n;i++){
node m=q[i];
//如果堆是空的(一开始)或者当前区间的左端点比任何一个分组右端点的最小值还小,那就得重新分入一个区间
if(heap.empty()||m.a<=heap.top()){
heap.push(m.b);
}
else{//如果不是,那么可以入堆,而且组要更新右端点
//尽量选择和右端点最小的那个一组(贪心的地方)也就是我原本思路中“选择可以的且离它最近的”
heap.pop();
heap.push(m.b);
}
}
//堆的元素个数就是组数
cout<<heap.size()<<endl;
return 0;
}
方法三
在看题解的时候,发现了一个十分厉害的思路:
把这个问题想象成活动安排问题
有若干个活动,第i个活动开始时间和结束时间是[a,b],同一个教室安排的活动之间不能交叠,求要安排所有活动,少需要几个教室?
有时间冲突的活动不能安排在同一间教室,与该问题的限制条件相同,即最小需要的教室个数即为该题答案。
我们可以把所有开始时间和结束时间排序,遇到开始时间就把需要的教室加1,遇到结束时间就把需要的教室减1,在一系列需要的教室个数变化的过程中,峰值就是多同时进行的活动数,也是我们至少需要的教室数。
代码
太厉害了啊是😭
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[2*N];
int main(){
int n;
cin>>n;
int l,r;
for(int i=1;i<=n;i++){
cin>>l>>r;
a[i*2-1]=l*2-1;
a[i*2]=r*2;//将所有端点映射到一维数组中
}
sort(a+1,a+1+2*n);
int ans=0;
int tmp=0;
for(int i=1;i<=2*n;i++){
if(a[i]%2){//如果是左端点,表明有活动开始,需要一间教室
tmp++;
ans=max(ans,tmp);
}
else{
tmp--;
}
}
cout<<ans;
return 0;
}