Living-Dream 系列笔记 第19期

Posted on 2024-03-03 18:42  _XOFqwq  阅读(1)  评论(0编辑  收藏  举报

Problem

T1

/*
思路:对于每一对L,R,标记[L,R)(注意左闭右开!),
并且求出最小的L(minl)和最大的R-1(maxr);
循环maxl~maxr,若被标记则最长连续挤奶时间+1,最长无人挤奶时间=0;
否则最长连续挤奶时间=0,最长无人挤奶时间+1,同时更新最大值。
*/
#include<bits/stdc++.h>
using namespace std;

int n;
int sum1,sum2,ans1=-1e9,ans2=-1e9;
int minl=1e9,maxr=-1e9;
bool vis[1000031];

int main(){
    cin>>n;
    for(int i=1,l,r;i<=n;i++){
        cin>>l>>r;
        minl=min(minl,l),maxr=max(maxr,r-1); //求minl和maxr
        for(int i=l;i<r;i++) vis[i]=1; //标记
    }
    for(int i=minl;i<=maxr;i++){ //统计最长连续挤奶时间
        if(vis[i]) sum1++;
        else sum1=0;
        ans1=max(ans1,sum1);
    }
    for(int i=minl;i<=maxr;i++){ //统计最长无人挤奶时间
        if(!vis[i]) sum2++;
        else sum2=0;
        ans2=max(ans2,sum2);
    }
    cout<<ans1<<' '<<ans2<<'\n';
    return 0;
}

T2

/*
思路:考虑贪心,设第n+1个金币在(0,0)位置,避免特判,
并且对所有金币按y坐标排序;
对于第i个与第i+1个金币,若x[i+1]-x[i]>y[i+1]-y[i](即需要走的时间大于下落时间),则立即输出Notabletocatch;
否则,若一直未出现此情况,输出Abletocatch。
*/
#include<bits/stdc++.h>
using namespace std;

int T,n;
struct node{
	int x,y;
}a[131];

bool check(){
	for(int i=1;i<=n;i++){
	    if(abs(a[i+1].x-a[i].x)>abs(a[i+1].y-a[i].y)) //若需要走的时间大于下落时间
	        return 0;
	}
	return 1;
}
bool cmp(node a,node b){
	return a.y<b.y;
}
string work(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
	a[n+1].x=0,a[n+1].y=0; //将第n+1枚硬币设为(0,0)
	sort(a+1,a+n+2,cmp); //按y坐标排序
	return check()?"Abletocatch\n":"Notabletocatch\n"; 
}

int main(){
	cin>>T;
	while(T--) cout<<work(); 
	return 0;
}

T3

/*
枚举k的值,对于每一个k,枚举子串起点并截取子串,
若一直没有出现过就输出当前的k即可。
*/
#include<bits/stdc++.h>
using namespace std;

int n;
map<string,bool> vis; 
string s;

int main(){
	cin>>n>>s;
	for(int i=1;i<=n;i++){ //枚举k的值
		bool f=1;
		vis.clear(); //清空map
		for(int j=0;j+i-1<s.size();j++){ //枚举子串起点,注意不能超过n
			string t=s.substr(j,i); //截取子串
			if(vis[t]){ f=0; break; } //若出现过了
			vis[t]=1; //标记
		}
		if(f){ cout<<i; break; } //若一直未出现输出当前的k
	}
	return 0;
}

T4

/*
思路:尝试将方程变为kx+b=0的形式,其中k为系数,b为常数,x为未知数。这样方程的结果为(-b)/k。
具体的,首先记录变量sgn、eq、num、hasnum,表示符号、在等式的哪一边、当前数字、刚才是否拼接了数字。
扫描一遍方程式,若si为-,则常数+=num*eq*sgn,并令sgn=-1,hasnum=num=0。+、=时同理。
若si为数字,则令num=num*10+(si-'0'),并令hasnum=0;
若si为字母,则若hasnum=1,则令系数+=num*eq*sgn,并令num=0;
否则,直接令系数+=eq*sgn。
并且需要令未知数字母=si,且hasnum=0。
*/
#include<bits/stdc++.h>
using namespace std;

string s;
bool hasnum; //刚才是否拼接数字
int sgn=1,eq=1,num; //符号、等号的哪一边、数字
double ans; //答案
char x; //字母
int b,k; //常数和系数

int main(){
	cin>>s;
	for(int i=0;s[i];i++){
		if(s[i]=='-'){ //符号类
			b+=eq*sgn*num;
			num=0,sgn=-1,hasnum=0;
		}
		if(s[i]=='+'){
			b+=eq*sgn*num;
			num=0,sgn=1,hasnum=0;
		}
		if(s[i]=='='){
			b+=eq*sgn*num;
			num=0,sgn=1,eq=-1,hasnum=0;
		}
		if(isdigit(s[i])) //数字类
			num=num*10+(s[i]-'0'),hasnum=1;
		if(islower(s[i])){ //字母类
            x=s[i];
			if(hasnum){ //刚刚拼接过数字
				k+=eq*sgn*num;
				num=0;
			}
			else
				k+=eq*sgn;
            hasnum=0;
		}
	}
    b+=eq*sgn*num; //注意加上最后的常数
    ans=(double)-b/(double)k; //计算答案
    if(ans==-0.0) ans=0; //特判
	cout<<x<<'='<<setprecision(3)<<fixed<<ans;
	return 0;
}

T5

/*
思路:所有牛能看到的牛的个数的总和,等于所有牛被看到的次数的总和。
同时,能看见这头牛的牛一定比这头牛高。
因此,我们考虑维护一个栈,里面的元素从栈顶到栈底单调递增,
这样就保证了从栈底到栈顶的每一头牛都能看见上面的所有牛。
于是每当有一头牛将要入栈时,就将身高<=它的牛全部弹出,
并将答案加上栈的大小(就是这头牛被看到的次数),再入栈即可。
这就是著名的单调栈算法,时间复杂度O(n)。
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,ans;
stack<int> s;

signed main(){
    cin>>n;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        while(!s.empty()&&x>=s.top()) s.pop(); //只要栈不为空,弹出身高<=当前牛的。
        ans+=s.size(); //答案累加栈的大小
        s.push(x); //入栈
    }
    cout<<ans;
    return 0;
}