Codeforces Round #425 (Div. 2)

本文解析了Codeforces Round #425 (Div.2)的四道题目,包括数学判断问题、字符串匹配问题、动态规划与扫描线算法解决的几何问题以及树上的路径计算问题。

比赛链接:Codeforces Round #425 (Div. 2)
A:

A/B Problem

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll n,k;
    cin >> n >> k;
    if(n/k%2LL==0) cout << "NO" << endl;
    else cout << "YES" << endl;
    return 0;
}

B:

字符串处理。。。容易写错

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool ok[26];
bool solve(string &s1,string &s, string &t)
{
    int l,r;
    for(l=0;s[l]!='*';++l)
        if((s[l]=='?'&&!ok[t[l]-'a'])||(s[l]!='?'&&s[l]!=t[l])) return false;
    for(r=1;s[s.length()-r]!='*';++r)
        if((s[s.length()-r]=='?'&&!ok[t[t.length()-r]-'a'])||(s[s.length()-r]!='?'&&s[s.length()-r]!=t[t.length()-r])) return false;
    s1=t.substr(l,(int)t.length()-r-l+1);
    return true;
}
int main()
{
    string s;
    cin >> s;
    for(auto ch : s) ok[ch-'a']=true;
    cin >> s;
    bool star=false;
    for(auto ch : s) if(ch=='*') star=true;
    int q;
    cin >> q;
    while(q--)
    {
        string t;
        cin >> t;
        if(star)
        {
            string s1;
            if(!star||t.length()<s.length()-1) cout << "NO" << endl;
            else if(!solve(s1,s,t)) cout << "NO" << endl;
            else
            {
                if(s1.length()==0) cout << "YES" << endl;
                else
                {
                    bool f=true;
                    for(auto ch : s1) if(ok[ch-'a']) f=false;
                    if(f) cout << "YES" << endl;
                    else cout << "NO" << endl;
                }
            }
        }
        else
        {
            bool f=true;
            if(s.length()!=t.length()) f=false;
            else for(int i=0;i<t.length();++i)
            {
                if(s[i]=='?')
                {
                    if(!ok[t[i]-'a']) f=false;
                }
                else if(s[i]!=t[i]) f=false;
            }
            if(f) cout << "YES" << endl;
            else cout << "NO" << endl;
        }
    }
    return 0;
}

C:

题意是线段上有 n 个人,分别有各自的初始坐标,速度以及行走方向。要求你找到一个炸弹的位置,这个炸弹会在一开始爆炸并向两边射出速度为 svi 的激光。如果人在与激光相遇时具有相同的速度和相同的方向,那么人的速度会增加 s 。求出最小的 t 使得在 t 时刻前,x=0 x=106 这两个点都被人经过。
可以二分时间 t ,设人的初始位置与人与激光相遇的位置的距离差为 d1 ,人与终点的距离差为 d 。如果dvit 那么无论炸弹放在哪个点都行。否则,如果 dvi+st ,那么可以推出炸弹的可行位置,是个线段。可以用扫描线来找出炸弹的可行位置。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
const int N=1e5+7;
int n;
const int L=1000000;
ld s;
ld v[N],d[N];
int dir[N],x[N];
struct Point
{
    int x,v,d;
    bool operator < (const Point &r) const
    {
        return x!=r.x?x<r.x:v>r.v;
    }
};
vector<Point> seg;
bool check(ld t)
{
    seg.clear();
    int ok[2];
    ok[0]=ok[1]=0;
    for(int i=0;i<n;++i)
    {
        if(d[i]/v[i]<=t) ok[dir[i]]=1;
        else if(d[i]/(v[i]+s)<=t)
        {
            ld d1=(t-d[i]/(v[i]+s))/(1/v[i]-1/(v[i]+s));
            ld off=d[i]-d1+d1*s/v[i];
            if(dir[i])
            {
                seg.push_back({ lround(max((ld)0,ceil(L-off))),1,dir[i] });
                seg.push_back({ x[i],-1,dir[i] });
            }
            else
            {
                seg.push_back({ x[i],1,dir[i] });
                seg.push_back({ lround(min((ld)L,floor(off))),-1,dir[i] });
            }
        }
        if(ok[0]&&ok[1]) return true;
    }
    sort(seg.begin(),seg.end());
    for(auto k : seg)
    {
        ok[k.d]+=k.v;
        if(ok[0]&&ok[1]) return true;
    }
    return false;

}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> s;
    for(int i=0;i<n;i++)
    {
        cin >> x[i] >> v[i] >> dir[i] ;
        --dir[i];
        d[i]=dir[i]?L-x[i]:x[i];
    }
    ld l=0,r=L;
    for(int i=0;i<50;++i)
    {
        ld m=(l+r)/2;
        if(check(m)) r=m;
        else l=m;
    }
    cout << fixed << setprecision(20) <<   r << endl;
    return 0;
}

D:

求出树上终点相同的两条链的公共长度,假设要求 (a,b) (b,c) 的公共长度,答案是 dis(a,b)+dis(b,c)dis(a,c)2 。可以用LCA来做。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int d[N],anc[N][20],k,n;
vector<int> adj[N];
void dfs(int u, int father, int deep)
{
    anc[u][0]=father;
    d[u]=deep;
    for(auto v : adj[u])
    {
        if(v==father) continue;
        dfs(v,u,deep+1);
    }
}
void init()
{
    dfs(1,0,0);
    for(int j=1;(1<<j)<n;j++)
    {
        k=j;
        for(int i=1;i<=n;++i)
            anc[i][j]=anc[i][j-1]?anc[anc[i][j-1]][j-1]:0;
    }
}
int lca(int u,int v)
{
    int res=0;
    if(d[u]<d[v]) swap(u,v);
    for(int i=k;i>=0;--i)
        if(d[u]-(1<<i)>=d[v])
            u=anc[u][i],res+=(1<<i);
    if(u==v) return res;
    for(int i=k;i>=0;i--)
        if(anc[u][i]!=anc[v][i])
        {
            u=anc[u][i];
            v=anc[v][i];
            res+=(1<<(i+1));
        }
    return res+2;
}
int dis(int s,int f,int t)
{
    return ((lca(s,f)+lca(t,f)-lca(s,t))>>1)+1;
}
int main()
{
    ios::sync_with_stdio(false);
    int q;
    cin >> n >> q;
    for(int u=2;u<=n;++u)
    {
        int v;
        cin >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    init();
    while(q--)
    {
        int a,b,c;
        cin >> a >> b >> c;
        int ans=0;
        ans=max(ans,dis(a,b,c));
        ans=max(ans,dis(a,c,b));
        ans=max(ans,dis(b,a,c));
        ans=max(ans,dis(b,c,a));
        ans=max(ans,dis(c,a,b));
        ans=max(ans,dis(c,b,a));
        cout << ans << endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值