B.线段的包含关系
题意
给出n个区间,判断时候有哪个区间是被包含在哪个区间的 ,如果有多个输出其中的一组。先输出被包含的区间(他的次叙数),再输出包含他的区间的次序输,如果没有输出的就输出-1 -1
思路
先按左边界从小到大排序,左边界相同的就再按右边界从大到小排序,如果再相同就按序号从小到大排序,可以给sort函数制定一种排序规则,这题我觉得我得背下来,既有结构体还有对sort函数制定排序规则的应用,排序完了,就判断如果一个点的下个点的右边界小于等于他就是包含于他的,输出就行了
代码
#include<iostream>
#include<algorithm>
using namespace std;
struct Node
{
int r,l,id;
}a[300010];
bool paixu(Node x,Node y)
{
if(x.l!=y.l)
return x.l<y.l;
else
{
if(x.r!=y.r)
return x.r>y.r;
else
return x.id<y.id;
}
}//给出一种排序规则用在sort函数里
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].l>>a[i].r;
a[i].id=i;
}
int f=0;
int j;
sort(a+1,a+1+n,paixu);//可以给sort制定排序规则 学到了
for(int i=2;i<=n;i++)
{
if(a[i].r<=a[i-1].r)
{
f=1;
j=i;
break;
}
}
if(f)
cout<<a[j].id<<" "<<a[j-1].id<<endl;
else
cout<<"-1 -1"<<endl;
return 0;
}
C.地下城还有lara
题意
就是给一个n行m列的网格,然后给你个给定的顺序走,从0 0 开始问走了k步之后的坐标
思路
都说是找规律,我就是每个情况求的,情况很多,代码里有注释
代码
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
int main(){
LL n,m,k;
scanf("%lld%lld%lld",&n,&m,&k);
if(k<=n-1) printf("%lld 1\n",1+k); //只在第一列
else if(k<=n+m-2){ //位于最后一行
k-=n-1;
printf("%lld %lld\n",n,1+k);
}
else{ //一般情况
k=k-(n-1)-(m-1);
LL t=k/(m-1);
LL r=k%(m-1);
if(r==0){
if(t%2) printf("%lld 2\n",n-t);
else printf("%lld %lld\n",n-t,m);
}
else{
if(t%2){
if(r==1) printf("%lld 2\n",n-t-1);
else printf("%lld %lld\n",n-t-1,r+1);
}
else{
if(r==1) printf("%lld %lld\n",n-t-1,m);
else printf("%lld %lld\n",n-t-1,m-r+1);
}
}
}
return 0;
}
D.心火牧日常计算
题意
给你n个随从,每个随从都有生命值和攻击力,有两种技能,第一个是使随从的生命值翻倍,还有一个技能就是使随从的攻击力等于生命值,输入n,a,b,n是随从的个数,a是一技能的使用次数,b是二技能的使用次数,然后再输入每个随从的生命值和攻击力,求经过技能处理后。所得随从攻击力总和的最大值
思路
a技能因为是使生命值翻倍,最大就是使一个随从连续翻倍他的生命值最大就成为 他的生命值乘2的a次方,然后就给他一次b技能使攻击力等于生命值就行,先按生命值减攻击力的大小排序,排好序好先把差较大的用b技能处理,然后还得记录效率最差的一个也就是处理的差值最最小的,注意并不是差值最小的因为可能差值最小的没有被b技能处理因为b技能可能会被用完的,处理完之后,预处理每一个随从,就预处理每一个随从对他们用a技能了之后哪个最大,求预处理的最大值就行了,预处理时也有几种情况:b还没用完的时候,和b用完了的时候,b用完了就要把效率最低的那次b,给用a技能的用。,还要看他用没用b技能,如果已经用了还得把加上的生命值减去,没用还得把加上的攻击力减去。
这题让我真正明白了什么是预处理,我大概现在认为就是假设对所有单位都做一遍这种处理然后求其中的最值。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=200010;
struct node
{
ll h,d;
int mk;
}p[maxn];
ll n,a,b;
bool cmp(node x,node y)
{
return x.h-x.d<y.h-y.d;
}//按照生命值减攻击力从小到大的顺序排序
ll quick_pow(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans*=x;
x*=x;
y>>1;
}
return ans;
}//快速幂因为那个翻倍的技能肯定只对一个用对好用到了所以最后乘2的a次幂
int main()
{
ios::sync_with_stdio(false);
memset(p,0,sizeof p);
cin>>n>>a>>b;
for(int i=1;i<=n;i++)
scanf("%lld %lld",&p[i].h,&p[i].d);
sort(p+1,p+n+1,cmp);
int last=n+1;//last 用来记录用b技能转化率最低的那个也就是最浪费的那一个
for(int i=n;i>=1;i--)
{
if(p[i].h-p[i].d>0&&b>0)
p[i].mk=1,b--;
else
break;
last--;
}
ll sum=0;
for(int i=1;i<=n;i++)
{
if(p[i].mk)
sum+=p[i].h;
else
sum+=p[i].d;
}//这时候的sum就是只用过b技能的sum,然后下面就是对每个随从进行预处理用a技能找出最大的
ll ans=sum;
for(int i=1;i<=n;i++)
{
ll tmp=p[i].h*quick_pow(2,a);
ll d=0;//d就是预处理用的,
if(p[i].mk)
d=sum-p[i].h+tmp;//用过一技能de减去生命值,没用过de减去攻击力
else if(tmp>p[i].d)
{
if(b>0)
d=sum-p[i].d+tmp;//b如果没用完直接给
else if(last<=n)
d=sum-p[last].h+p[last].d-p[i].d+tmp;//b如果用完了就应该把转化率最低的那次b不用了
//然后给当前用a的用b
}
ans=max(ans,d);
}
cout<<ans<<endl;
return 0;
}
F.法法要穿过大门
题意
就是在直角坐标系的第一象限中,设直线y=x为一堵墙,然后从起点(0,0)开始,给一串字符串全是由UR组成,U表示网上走1,R表示往右走1,问穿过这个墙的次数(必须是从墙的另一边到达了另一边才是穿过墙)
思路
区域分为上方下方,判断他刚到上方的时候之前在下方就加1或者是之前在下方的时候原先在上方,这时候我们就可以引入一个标志变量,之前如果在下方的时候就让f=-1,然后当判断走到上方的时候f是否为-1,如果是的话就说明前后状态不一样那么久加一,同样如果之前在上方的话就让他为1,判断当他跑到下方的时候f如果为1就是前后状态不一样也是加1
代码
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
char s[100010];
int n;
cin>>n;
for(int i=0;i<n;i++)cin>>s[i];
int x=0,y=0,f=0,sum=0;
for(int i=0;i<n;i++)
{
if(s[i]=='U')y++;
if(s[i]=='R')x++;
if(x>y&&f==-1)sum++;//用f判断这一次是否与上次再不同地区域,之前在下方的时候让f=1
//如果在下次再上方了就看时候f=1即判断之前是否在下方
if(x<y&&f==1)sum++;
if(x>y)f=1;
if(x<y) f=-1;
}
cout<<sum<<endl;
return 0;
}