2022/5/8

F-净_牛客小白月赛49 (nowcoder.com)

如果没有M的话那么最后的长度一定是n*k+3,有M的话可以发现第一次出现M后产生的点都会是对称的,所以以M后产生的点的父节点的父节点为根,加上两边的对称长度去和n*k+3比较,最大者就是答案;

【比赛题目讲解】牛客小白月赛49(fried-chicken)_哔哩哔哩_bilibili

#include
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll t,n,k;
char s[100005];
int main(){
	//freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&k);
        scanf("%s",s+1);
        ll flag=0,le=n*k;
        ll ans=n*k+3,m=-1;
        for(int i=1;i<=n;i++){
            if(s[i]=='M'){m=i;break;}
        }
        //if(!flag) m=-2;
        //cout<

Vlad and Unfinished Business

转化为以x为根经过k个中间点最后到达y所需要的最少路程,进而再转化到从x到y的路径中,路径中所有点的子树中距离该点最远的中间点到该点的距离之和再加上x到y的距离,具体思路还是看这吧,主要是懒得画图了,,

Codeforces Round #787 (Div. 3) E(贪心) F(dfs) - 知乎 (zhihu.com)

#include
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll t,n,k,x,y,a[200005],path[200005],son[200005];
vectorv[200005];
void dfs1(ll u,ll fa){
    for(int i=0;i0)
            res+=1+dfs2(j,u)+1;//看这图手算一下
    }
    return res;
}
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&k);
        scanf("%lld%lld",&x,&y);
        for(int i=1;i<=n;i++) v[i].clear(),path[i]=0,son[i]=0;
        for(int i=1;i<=k;i++){
            scanf("%lld",&a[i]);
            son[a[i]]=1;
        }
        for(int i=1;i

三段式 - 题目 - Daimayuan Online Judge

想了那么久想不出来,看了题解才知道忘了一个很重要的条件,既然能分成三段那就说明总的sum可以被2整除呀,,,所以只要前缀和等于sum/3,后缀和等于sum/3,那中间的部分也一定等于sum/3,所以记录后缀和等于sum/3的次数枚举前缀和就可以了,需要注意的是中间段不能为空;

 (前缀和) 代码源每日一题 Div2 三段式 - 知乎 (zhihu.com)

#include
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll n,a[100005];
mapmp;
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%lld",&n);
	ll k=0;
	for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        k+=a[i];
	}
	k=k/3;
	ll ans=0,su=0,cnt=0;
	for(int i=n;i>=1;i--){
        su+=a[i];
        if(su==k) cnt++;
        mp[i]=cnt;
	}
	su=0;
	for(int i=1;i<=n;i++){
        su+=a[i];
        if(su==k) ans+=max(mp[i+2],0LL);
	}
	printf("%lld\n",ans);
	return 0;
}

P6510 奶牛排队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

一个区间内A是最小值,B是最大值,那么A一定是该区间的后缀最小值,B一定是该区间的后缀最大值,可以用两个单调栈来维护;另外可以看出从B开始向前数第二个后缀最大值也就是第一个比B大的数一定是在A的后面,那么我们新枚举一个B时,在压入栈顶前,栈顶的元素是B之前且比B大的一个数,只要我们的A在这个数后面且是当前的后缀最小值,那么这个A就是合法的,那么我们就可以在最小值这个栈里二分找到这个A的下标,那也就找出了这个A-B的区间,更新区间的最大长度就可以了

P6510 奶牛排队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 

#include
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll n,a[100005],mx[100005],mn[100005];
int main(){
	//freopen("in.txt","r",stdin);
	ll tx=0,tn=0,ans=0;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        while(tn&&a[mn[tn]]>=a[i]) tn--;//这个等号就把重复元素给排除了
        while(tx&&a[mx[tx]]

你可能感兴趣的:(笔记,蓝桥杯,c++,职场和发展)