hey_left 5 Codeforces Round 898 (Div. 4) 续
F.
先把序列分割成一个个满足条件的子序列
然后二分长度,去判断子序列是否满足长度,若有一个满足,这个答案可行,判断更长的长度
debug:
存下的子序列忽略了单个元素,单个元素也是一个子序列,把每个元素单独作为一个子序列后可以ac
题解有更简单的做法,双指针,直接遍历一遍得到答案
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
int fruit[N],height[N];
int pre[N];
void solve(){
int n,k;cin>>n>>k;
vector<pair<int,int>>tmp;
vector<vector<pair<int,int>>>v;
for(int i=1;i<=n;i++){
cin>>fruit[i];
pre[i]=pre[i-1]+fruit[i];
}
for(int i=1;i<=n;i++){
cin>>height[i];
tmp.push_back({height[i],i});
v.push_back(tmp);
tmp.clear();
}
int flag=0;
for(int i=2;i<=n;i++){
if(height[i-1]%height[i]==0){
if(flag==0){
flag=1;
tmp.push_back({height[i-1],i-1});
}
tmp.push_back({height[i],i});
}else {
flag=0;
if(tmp.size()) {
v.push_back(tmp);
tmp.clear();
}
}
if(i==n){
if(tmp.size())v.push_back(tmp);
}
}
// for(auto t:v){
// for(int i=0;i<t.size();i++){
// cout<<t[i].first<<' ';
// }
// cout<<'\n';
// }
int l=1,r=n,mid;
bool success=0;
int ans=0;
while(l<=r){
success=0;
mid=(l+r)/2;
int sum=0;
for(int i=0;i<v.size();i++){
for(int j=0;j+mid-1<v[i].size();j++){
sum=pre[v[i][j+mid-1].second]-pre[v[i][j].second-1];
if(sum<=k){
success=1;
break;
}
}
if(success==1)break;
}
if(success==1){
l=mid+1;
ans=max(ans,mid);
}else r=mid-1;
}
cout<<ans<<'\n';
}
signed main(){
int hey_left=1;
cin>>hey_left;
while(hey_left--){
solve();
}
}
G.
AB-BC,可以发现,消掉一个B,又补上一个B,若是AAAAB形式,一个B可以消掉前面所有的A,同时因为后面一个C,它就只能向前拓展,无法向后拓展
BA-CB,同理,只能向后拓展,无法向前拓展
若是AAABAA型的,那么要考虑B往哪一个方向拓展
绕了一些弯子,其实很简单
若以B开头或结尾,那么一定可以消掉所有的A
只有两头都是A的时候才要继续考虑
若中间出现了连续的大等于两个以上的B,那么也可以全部消掉(一个B拓展一边)
若没有则所有的a的数量-最小的连续a的长度即为答案(一定会剩下一段连续的a,让贡献最小的不被拓展即可)
#include <bits/stdc++.h>
using namespace std;
void solve(){
string s;cin>>s;
int cnt_a=0;
int cnt_b=0;
int ma=0;
int mi_a=0x3f3f3f3f,tmp_a=0;
for(int i=0;i<s.size();i++){
if(s[i]=='A'){
tmp_a++;
cnt_a++;
ma=max(ma,cnt_b);
cnt_b=0;
}
if(s[i]=='B'){
cnt_b++;
mi_a=min(mi_a,tmp_a);
tmp_a=0;
}
if(i==s.size()-1){
mi_a=min(mi_a,tmp_a);
}
}
if(s[0]=='B'||s[s.size()-1]=='B'){
cout<<cnt_a<<'\n';
return ;
}
if(ma>=2){
cout<<cnt_a<<'\n';
}else{
cnt_a-=mi_a;
cout<<cnt_a<<'\n';
}
}
signed main(){
int hey_left=1;
cin>>hey_left;
while(hey_left--){
solve();
}
}
H.
n个点n条边且联通,那么图里有且仅有一个环
若a,b两点在环上,那么a永远追不上b
考虑不都在换上的情况
那么b最优是想跑到环上去,那么a就要阻止它
有一个点事自己没想到的:
b进入环的那个点tag是唯一的,不然就不止一个环了
然后分别算出a,b到tag的距离,若a的小等于b的,那么是NO,否则为YES
还有一个特判:
若a,b在同一个位置,那么一定是NO(都在环上也不行)
学到用拓扑找环:拓扑完后,剩下的度为正数的点一定在环上
找距离用的dij
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,a,b;
vector<int>g[N];
int rd[N];
int tag;
void top_sort(){
queue<int>q;
for(int i=1;i<=n;i++){
if(rd[i]==1)q.push(i);
}
while(q.size()){
int k=q.front();q.pop();
rd[k]--;
for(int i=0;i<g[k].size();i++){
rd[g[k][i]]--;
if(rd[g[k][i]]==1){
q.push(g[k][i]);
}
}
}
}
void find_tag(int u,int fa){
if(rd[u]>0){
tag=u;
return ;
}
for(int i=0;i<g[u].size();i++){
int y=g[u][i];
if(y==fa)continue;
find_tag(y,u);
}
}
int vis[N],dist[N];
void init(){
for(int i=1;i<=n;i++){
g[i].clear();
rd[i]=0;
}
}
void dij(){
for(int i=1;i<=n;i++){
dist[i]=0x3f3f3f3f;
vis[i]=0;
}
dist[tag]=0;
vis[tag]=1;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
q.push({0,tag});
while(q.size()){
auto t=q.top();q.pop();
vis[t.second]=1;
int distance=t.first,ver=t.second;
for(int i=0;i<g[ver].size();i++){
int k=g[ver][i];
if(vis[k])continue;
if(dist[k]>distance+1){
dist[k]=distance+1;
q.push({dist[k],k});
}
}
}
}
void solve(){
init();
cin>>n>>a>>b;
for(int i=1,u,v;i<=n;i++){
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
rd[u]++;rd[v]++;
}
if(a==b){
cout<<"NO"<<'\n';
return ;
}
top_sort();
if(rd[a]>0&&rd[b]>0){
// cout<<rd[a]<<' '<<rd[b]<<'\n';
cout<<"YES"<<'\n';
return ;
}
find_tag(b,0);
// for(int i=1;i<=n;i++){
// if(rd[i]>0)
// }
//cout<<tag<<'\n';
dij();
if(dist[a]<=dist[b]){
cout<<"NO"<<'\n';
}else cout<<"YES"<<'\n';
//cout<<dist[a]<<' '<<dist[b];
}
signed main(){
int hey_left=1;
cin>>hey_left;
while(hey_left--) {
solve();
}
return 0;
}