艰苦卓绝的做题过程x2
1 怎么看电影&zdx看电影&活动安排
注:“怎么看电影”和“活动安排”是同一个题,由于洛谷没有该题,故使用了之前自己上传的题目。“zdx看电影”是多组数据,每组数据中做法相同。
problem
有(n)个活动,分别有起止时间([x,y)),两个活动([a,b),[c,d))不想交,则叫做这两个活动相容。求这(n)个活动中互相相容的活动个数最大值。
solution
贪心考察。把所有的活动起止时间映射在数轴上,我们可以选择结束时间尽可能早的点,这样可以继续选择更早开始的活动,使得全局更优。代码实现显然,复杂度(O(n)),多组数据(O(Tn))
thoughts
debug:t1写成t。
100pts:贪心。
code
活动安排&怎么看电影
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read() {
long long a = 0, op = 1;
char c = getchar();
while (c > '9' || c < '0') {
if (c == '-')
op = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
a *= 10, a += c ^ 48, c = getchar();
}
return a * op;
}
struct node {
int num, l, r;
} a[1000005];
int t;
int k;
bool cmp1(node x, node y) { return x.r < y.r; }
int ans = 1, t1;
int main() {
k = read();
for (int i = 1; i <= k; i++) a[i].l = read(), a[i].r = read();
sort(a + 1, a + k + 1, cmp1);
t1 = a[1].r;
for (int i = 2; i <= k; i++)
if (a[i].l >= t1)
ans++, t1 = a[i].r;
printf("%d
", ans);
return 0;
}
zdx看电影(多组数据)
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read(){
long long a=0,op=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
return a*op;
}
struct node {
int num,l,r;
}a[1000005];
int t;
int k;
bool cmp1(node x,node y){
return x.r<y.r;
}
int main(){
t=read();
while(t--){
k=read();
for(int i=1;i<=k;i++) a[i].num=read(),a[i].l=read(),a[i].r=read();
//for(int i=1;i<=k;i++) printf("test:%d %d
",a[i].l,a[i].r);
sort(a+1,a+k+1,cmp1);
//for(int i=1;i<=k;i++) printf("testxxx:%d %d
",a[i].l,a[i].r);
int t1=a[1].r,ans=1;
for(int i=2;i<=k;i++)
if(a[i].l>=t1) ans++,t1=a[i].r;
printf("%d
",ans);
for(int i=1;i<=k;i++) a[i].l=0,a[i].r=0;
}
return 0;
}
2 智力大冲浪
problem
有(n)个活动,每个活动没有完成扣除的金额为(p_i),每个活动的完成时限为(q_i),在完成时限内没有完成会扣除相应金额。给定金额(m),求剩余的钱的最大值。
solution
如果遇到一个时限为(k)的活动,我们要尽可能的把它放到能放的(le k)的位置。如果不能放,我们就把他放到最大的一个空时间段,这样避免影响之后的结果,也不会对结果产生影响,因为如果这件事情做不完,在任何情况下做不完扣除的钱都一样。
thoughts
100pts:一次AC。
code
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read(){
long long a=0,op=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
return a*op;
}
int tim[505],n,s,x,mon[505],m;
struct node{
int tim,mon;
}a[505];
int done[505];
bool cmp1(node x,node y){
return x.mon>y.mon;
}
int main(){
m=read();n=read();
for(int i=1;i<=n;i++) a[i].tim=read();
for(int i=1;i<=n;i++) a[i].mon=read();
sort(a+1,a+n+1,cmp1);
for(int i=1;i<=n;i++){
x=1;
for(int j=a[i].tim;j>=1;j--){
if(done[j]==0) {x=0,done[j]=1;break;}
}
if(x){
for(int k=n;k>=1;k--)
if(done[k]==0) {done[k]=1;break;}
s+=a[i].mon;
}
}
printf("%d",m-s);
return 0;
}
3 雷达安装
problem
平面直角坐标系中,第I、II象限内有(n)个点,在(x)轴上寻找最少的(k)个点,使得以它们为圆心,(d)为半径的圆将所有的点覆盖。
solution
以每个点为圆心,d为半径做圆,每个点可以在(x)轴上得到一个区间,这样就转换成了在(x)轴上选点,使得每个区间内都至少有一个点。
我们按照右端点排序,如果下一个区间的右端点在前一个里面,我们可以跳过,否则我们就选择右端点最旁边的那个点(也就是那个点),显然这样更优。复杂度(O(n))。
thoughts
100pts:一次AC。
code
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read(){
long long a=0,op=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
return a*op;
}
const int maxn=1e4+5;
int n,d,ans,x[maxn],y[maxn];
double l[maxn],r[maxn],temp;
struct node{
double l,r;
}a[maxn];
double cmp(node a,node b){return a.r<b.r;}
int main(){
n=read(),d=read();
for(int i=1;i<=n;i++) x[i]=read(),y[i]=read();
for(int i=1;i<=n;i++)
a[i].l=x[i]-sqrt(d*d-y[i]*y[i]),
a[i].r=x[i]+sqrt(d*d-y[i]*y[i]);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
if(i==1) temp=a[i].r,ans++;
else{
if(temp>=a[i].l) continue;
else ans++,temp=a[i].r;
}
}
printf("%d",ans);
return 0;
}
4 整数区间
problem
给定(n)个区间([a_i,b_i]),选择最少的点,使得每个区间内至少有两个点,求选择点的个数。
solution
把区间先按右端点从小到大排序,开两个变量来记录位置(保证x < y)
如果区间右端点大于y,则这个区间者少有两个数被劝进集合中了,continue掉就好了
如果区间的右端点在x和y之间,把x变成y,y变成这个区间的左端点,同时ans++
如果区间的右端点小于x,x变成区间的左端点,y变成区间的右端点,同时ans+=2
thoughts
100pts:一次AC。
code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int a;
int b;
};
node m[1000];
bool cmp(node a,node b)
{
if(a.a != b.a)
{
return a.a < b.a;
}
else
return a.b < b.b;
}
int main()
{
int n,f1,f2,tot = 0;
cin>>n;
for(int i = 1;i <= n;i++)
{
cin>>m[i].a>>m[i].b;
}
sort(m + 1,m + n + 1,cmp);
f1 = m[n].a;
f2 = m[n].a + 1;
tot += 2;
for(int i = n - 1;i > 0;i--)
{
if(m[i].b < f1)
{
tot += 2;
f1 = m[i].a;
f2 = f1 + 1;
}
else if(m[i].b < f2)
{
tot ++;
f2 = f1;
f1 = m[i].a;
}
}
cout<<tot<<endl;
return 0;
}