Codeforces Round #620 (Div. 2) 题解

A. Two Rabbits

题意:
求左右两只分别能跳a,b距离的兔子,是否能在同一点,如果能求最短时间。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int T;
    cin>>T;
    while(T--){
        int x,y,a,b;
        cin>>x>>y>>a>>b;
        if((y-x)%(a+b)==0){
            cout<<(y-x)/(a+b)<<'
';
        }
        else puts("-1");
    }
    return 0;
}

Longest Palindrome

题意:
在n长度相同个字符串中选取构造一个最长的回文串。
思路:
暴力枚举每个字符串的方向相等的字符串,如果存在两个字符串分别构造在对称的左右位置,再找是否存在一个没有配对的回文串构造在中间。

#include<bits/stdc++.h>
using namespace std;
string s[101];
int p[101];
string ans;
int main(){
    int t,n;
    cin>>t>>n;
    for(int i=1;i<=t;++i){
        cin>>s[i];
        for(int j=1;j<i;++j){
            if(p[j]) continue;
            int f=0;
            for(int k=0;k<n;++k){
                if(s[j][k]!=s[i][n-k-1]) {
                    f=1;
                    break;
                }
            }
            if(!f){
                  p[j]=i;
                  p[i]=j;
                  ans+=s[j];
            }
        }
    }
    int f=0;
    for(int i=1;i<=t;++i){
        if(p[i]) continue;
        int flag=0;
        for(int j=0;j<n/2;++j){
            if(s[i][j]!=s[i][n-j-1]){
                flag=1;break;
            }
        }
        if(flag==0){
            f=i;
            break;
        }
    }
    int res=(int)ans.size()*2+(f>0?(int)s[f].size():0);
    if(res==0){
        cout<<0<<endl;
        return 0;
    }
    else cout<<res<<endl;
    cout<<ans;
    if(f>0) cout<<s[f];
    for(int i=(int)ans.size()-1;i>=0;--i){
        cout<<ans[i];
    }
    return 0;
}

C. Air Conditioner

题意:饭店里按会按时间出现n个客人,每个客人对温度的要求在一个特定的范围内,饭店里的空调每分钟可以+1,-1以及保持不变。求是否存在满足所有客人都满意的情况。
思路:贪心来想,每个客人出现时,都将温度控制在该客人可以接受的范围内,为了应对后面的客人范围需要越大越好。直到出现从对于上一个到下一个客人可以调控到的最大范围无法满足下一个客人时无解。

#include<bits/stdc++.h>
using namespace std;
struct ac{
    int t,l,h;
}a[101];
bool cmp(ac a1,ac a2){
    return a1.t<a2.t;
}
void solve(int n,int m){
    int nl=m,nh=m,now=0;
    for(int i=1;i<=n;++i){
        int p=a[i].t-now;
        now=a[i].t;
        if(nl-p>a[i].h||nh+p<a[i].l){
            cout<<"NO
";
            return ;
        }
        if(nl>a[i].l+p){
            nl-=p;
        }
        else nl=a[i].l;
        if(nh<a[i].h-p) {
            nh+=p;
        }
        else {
            nh=a[i].h;
        }
    }
    cout<<"YES
";
}
int main(){
    int T;
    cin>>T;
    while(T--){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;++i){
            cin>>a[i].t>>a[i].l>>a[i].h;
        }
        sort(a+1,a+1+n,cmp);
        solve(n,m);
    }
    return 0;
}

D. Shortest and Longest LIS

题意:
给出n个'<','>'组成的字符串,正在这些字符串中插入n+1一个1~n+1不重复的数字序列满足这些大小号,且分别构造出上升子序列最短和最长的序列。
思路:对于最短的lis序列,我们可以想到让右边的数字尽量大于右边的,那么对于">><>>",构造出653421这样的序列.同理最长lis序列,我们让右边的数字尽量小于左边的,那就构造出321654这样的。说明一下最大的具体构造方法:存下'>'由'<'隔开的连续区间,在'>'内让从小开始添加,如上面的例子(1,2)区间内从3开始添加到1在下一个区间从4开始。
那么最短的构造则相反了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
char s[maxn];
int Min[maxn],Max[maxn];
struct ac{
    int l,r;
};
vector<ac> v;
int n;
void solve_Max(){
    int l=1;
    v.clear();
    for(int i=1;s[i];++i){
        if(s[i]=='<') {
           v.push_back((ac){l,i});
            l=i+1;
        }
    }
    v.push_back((ac){l,n});
    int st=0,now=0;
    for(int i=0;i<(int)v.size();++i){
        int sz=v[i].r-v[i].l+1;
        for(int j=st+sz;j>st;--j){
            Max[++now]=j;
        }
        st=st+sz;
    }
    for(int i=1;i<=n;++i){
        cout<<Max[i]<<" ";
    }
    cout<<endl;
}
void solve_Min(){
    int l=1;
    v.clear();
    for(int i=1;s[i];++i){
        if(s[i]=='>') {
           v.push_back((ac){l,i});
            l=i+1;
        }
    }
    v.push_back((ac){l,n});
    int st=n,now=0;
    for(int i=0;i<(int)v.size();++i){
        int sz=v[i].r-v[i].l+1;
        for(int j=st-sz+1;j<=st;++j){
            Min[++now]=j;
        }
        st=st-sz;
    }
    for(int i=1;i<=n;++i){
        cout<<Min[i]<<" ";
    }
    cout<<endl;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        scanf("%s",s+1);
        solve_Min();
        solve_Max();
    }
    return 0;
}

E. 1-Trees and Queries

题意:在一棵树上做q次查询:假设增加一条从x连接y的边,是否存在a-b的距离为k的路径(每次查询后增加的边会删去)。
思路:首先想到若a-b有长度为p的最短距离,那么就有p+2+4+...+2o的路径,因为可以无限折回,那么如果问是否有从a-b长度为k的路径只需要判断p和k的奇偶性和p是否小于等于k满足这两点就是存在。那么再考虑增加一条边后情况就多了两种可能(a-x-y-b)和(a-y-x-b),因为x-y边可能是违反树的形状的需要单独拿出来。这样只要求一下这三种情况下a到b的距离是否存在一个满足上面说的条件。树上两点间的距离可以用lca求。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int anc[maxn][30],dep[maxn];
int head[maxn],cnt;
struct ac{
    int v,nex;
}edges[maxn*2];
void init(){
    memset(head,-1,sizeof head);
    cnt=0;
}
void addedge(int u,int v){
    edges[++cnt]=(ac){v,head[u]};
    head[u]=cnt;
}
void dfs(int u,int pre,int d){
	anc[u][0]=pre;
	dep[u]=d;
	for(int i=head[u];~i;i=edges[i].nex){
		int v=edges[i].v;
		if(v==pre) continue;
		dfs(v,u,d+1);
	}
}
void init_lca(int n){
	for(int j=1;j<log(n)/log(2)+1;j++){
		for(int i=1;i<=n;i++){
			anc[i][j]=anc[anc[i][j-1]][j-1];
		}
	}
}
int lca(int x,int y,int n){
	int xx=x,yy=y,comanc;
	int h=dep[x]-dep[y];
	if(h<0){
		swap(x,y);
		h=-h;
	}
	for(int i=0;h>0;++i){
		if(h&1) x=anc[x][i];
		h>>=1;
	}
	if(x==y) comanc=x;
	else {
		for(int i=log(n)/log(2);i>=0;--i){
			if(anc[x][i]!=anc[y][i]){
				x=anc[x][i];
				y=anc[y][i];
			}
		}
		comanc=anc[x][0];
	}
	return comanc;
}
int dis(int x,int y,int n){
    //cout<<"---"<<lca(x,y,n)<<endl;
    return dep[x]+dep[y]-2*dep[lca(x,y,n)];
}
bool check(int x,int y){
    if(x%2==y%2&&x>=y) return true;
    return false;
}
int main(){
    init();
    int n,u,v;
    cin>>n;
    for(int i=1;i<n;++i){
        cin>>u>>v;
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1,-1,1);
    init_lca(n);
    int q,x,y,a,b,k;
    cin>>q;
    while(q--){
        cin>>x>>y>>a>>b>>k;
        int res1=dis(a,b,n);
        int res2=dis(a,x,n)+1+dis(y,b,n);
        int res3=dis(a,y,n)+1+dis(x,b,n);
        if(check(k,res1)||check(k,res2)||check(k,res3)){
            puts("YES");
        }
        else puts("NO");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jjl0229/p/12517255.html