2022/5/8

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

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

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

#include<bits/stdc++.h>
#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<<m<<endl;
        if(m!=-1) ans=max(ans,(le-m+1LL)*2LL+3LL);
        printf("%lld\n",ans);
    }
	return 0;
}

Vlad and Unfinished Business

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

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

#include<bits/stdc++.h>
#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];
vector<ll>v[200005];
void dfs1(ll u,ll fa){
    for(int i=0;i<v[u].size();i++){
        ll j=v[u][i];
        if(j==fa) continue;
        dfs1(j,u);
        son[u]+=son[j];
        path[u]|=path[j];
    }
}
ll dfs2(ll u,ll fa){
    ll res=0;
    for(int i=0;i<v[u].size();i++){
        ll j=v[u][i];
        if(j==fa) continue;
        if(!path[j]&&son[j]>0)
            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<n;i++){
            ll u,vv;
            scanf("%lld%lld",&u,&vv);
            v[u].push_back(vv);
            v[vv].push_back(u);
        }
        path[y]=1;
        dfs1(x,0);
        ll ans=0;
        for(int i=1;i<=n;i++){
            if(path[i]) ans+=dfs2(i,0);
        }
        printf("%lld\n",ans+count(path+1,path+n+1,1)-1);
    }
	return 0;
}

三段式 - 题目 - Daimayuan Online Judge

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

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

#include<bits/stdc++.h>
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll n,a[100005];
map<ll,ll>mp;
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<bits/stdc++.h>
#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]]<a[i]) tx--;//这里没有也无所谓,有重复的话最后算区间长度为0
        ll id=upper_bound(mn+1,mn+tn+1,mx[tx])-mn;
        if(id<=tn) ans=max(ans,i-mn[id]+1);
        mn[++tn]=i;
        mx[++tx]=i;
	}
	printf("%lld\n",ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值