Codeforces Round#668(Div。2)AD問題の解決策

Codeforces Round#668(Div。2)ADの問題解決策
//評価値2033/2184で書かれている
//最近小さな休暇をとり、最近自宅に多くのものがあったが、この問題の解決策を補うために今まで遅れていた。//
今日学校に戻るアップ

コンテストリンク:https://codeforces.ml/contest/1405質問
A
単純な思考の水の質問

質問は、長さnの配置に対して、この長さnの配置で隣接する2つの各数値の合計を計算するための特別な操作Fingerprintf演算を定義することを意味します(明らかに、このような演算はn-1の数値を取得します)、ソートの結果。
順列aが与えられたら、aと同じ長さの順列bを作成する必要があります。これにより、2つの順列は、fingerprintf操作で同じ結果になります。

同じ値の数値が同じ回数出現する限り、最終結果がソートされることに気づきました。つまり、数値の順序は関係ありません。
その後、元の配置を逆に直接出力できます...説明なし

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        vector<int>num(n);
        for(int i=n-1;i>=0;i--) cin>>num[i];
        for(int i=0;i<n;i++)
        {
    
    
            if(i) cout<<' ';
            cout<<num[i];
        }
        cout<<endl;
    }
}

質問B
単純な思考、実行、貪欲

質問は、長さnのシーケンスnum []があり、シーケンス内のすべての数値の合計が0であることを意味します。
ここでの目標は、いくつかの操作を実行した後、シーケンス内のすべての数値を0にすることです。
各操作について、2つの添え字iとjを選択し、num [i]に対して-1操作を実行し、num [j]に対して+1操作を実行できます。i<jの場合、この操作はコストがかかりません。i> jの場合、この操作には1枚のコインが必要です。
次に、消費するコインの最小数を見つける必要があります。

それを貪欲に考えてみましょう。左から右に見ていきます。表示される正の部分は現在の位置の右側にある負の数で消費せずに使用でき、負の部分は現在の位置の左側の整数でのみ使用できます。操作を消費します。
非消費操作を可能な限り使用するという考えでは、ポジションがより否定的であるほど、それは不利になります。したがって、貪欲な戦略を直接採用し、tempを使用して現在の位置の左側に現れる正の数を記録し、負の数でコストのかからないオフセット操作を実行できます。このプロセスでtemp <0が表示された場合、現在の位置の負の数には左側に正の数がなく、消費せずにオフセットできることを意味します。コインの消費を相殺するために右側に正の数をオフセットする必要があります。 tempの絶対値は最後の回答の数に達し、tempはゼロに設定されます。

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        vector<ll>num(n);
        for(auto &x:num) cin>>x;
        ll ans=0;
        ll temp=0;//temp记录我们当前位置左侧还有多少的正数可用
        for(int i=0;i<n;i++)
        {
    
    
            temp+=num[i];//下面的if运算保证了temp一定不是负数
            //temp与当前位置上的数字进行加法运算,如果num[i]是负数则正是题意中无消耗的操作
            if(temp<0)//如果出现了无法被无消耗操作除去的负数部分,则必然要与后面的正数进行有消耗的操作
                //此处累加temp的绝对值到答案上,并清零
            {
    
    
                ans-=temp;
                temp=0;
            }
        }
        if(temp<0) ans-=temp;
        cout<<ans<<endl;
    }
}

質問C
簡単な結論、貪欲、実装

質問は、長さnの文字列sが与えられた場合、文字列sには「0」、「1」、および「?」の3文字しか含まれないことを意味します。そして、偶数kが与えられた場合、文字列sの文字「?」を0または1に置き換えて、文字列sの長さkのすべての連続する部分文字列、および部分文字列の0と1を満たすことができるかどうかを尋ねます数値は等しい、つまりすべてk / 2です。

最初に小さな結論をプッシュし、

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=3e5+7;

char firt[maxn];//firt[x]记录字符串s的下标i中,所有满足i%k=x的i,对应的字符是否相同,初始为'?'
//上述条件的所有字符相同,是字符串s的所有长度为k的子串中,0和1出现次数相同的充要条件
//这个条件是题目限定的所有长度为k子串中,0出现的次数均等于1出现的次数这个条件的弱化版本,为前置条件
int n,k;
string s;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n>>k>>s;
        for(int i=0;i<k;i++) firt[i]='?';
        bool flag=1;
        for(int i=0;i<n;i++)
        {
    
    
            if(firt[i%k]=='?') firt[i%k]=s[i];//如果当前firt[i]仍然为'?"代表没有出现固定的0或者1
            else if(s[i]!='?'&&firt[i%k]!=s[i]) flag=0;
            //如果firt[i%k]已经是0或者1了,而s[i]不为'?'且不与firt[i%k]相同的话则出现冲突,直接flag置零
        }
        int sum0=0,sum1=0;
        for(int i=0;i<k;i++)//再检测,每段长度为k的子串中,目前已经确定必须有的0和1各自有多少个
        {
    
    
            if(firt[i]=='0') sum0++;
            if(firt[i]=='1') sum1++;
        }
        if(sum0>k/2||sum1>k/2) flag=0;//如果0或者1出现的个数超过了长度k的一半,同样是不满足条件的
        //此处与firt数组实现的条件一同,构成了题目要求的条件
        if(flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

質問D
木の上のゲーム

質問は、ノード数がnの数値で、アリスとボブがそれぞれポイントaとbにいることを意味します。アリスから始まり、質問に答えて動き始めます。ある時点でアリスとボブが同じ位置にいる場合はアリスが勝利し、そうでない場合はボブが勝利します。アリスは毎回現在位置daから最も遠くに移動でき、ボブは毎回現在位置dbから最も遠い位置に移動できます。

ゲームに関しても、最も基本的な状況から始めます。

まず、アリスは次の動きにどうやって勝つことができますか。つまり、2つの位置間の距離がdis_ab <= daの場合、アリスはボブの位置まで直接歩いて1つの動きで勝つことができます。

その後、ツリー上ではなく、Lノードを持つ直線上にいると考えてみましょう。2 ×\ times× da> = L-1の場合、アリスは最初にこの線の中央の位置まで歩くことを選択でき、アリスは次の移動でこの線の任意の位置まで歩くことができます。この時点で、アリスはボブがどこにいても勝つことができます。
次に、ツリーについて考えます。ツリーがツリーの場合、重なり合う線の数も表示されます。ツリーの直径xは、最も長いラインの長さであり、2×\ timesだけが必要です× da> = x、アリスは上記の戦略を採用して勝利を確実にすることができます。

次に、2 ×\ times× da <x、アリスは上記の戦略では勝利できません。
同様に、私たちはまだ直線について考えていますが、ボブの場合、この直線上でアリスの同じ側に留まると、アリスはその辺の長さを継続的に短くして近づき続け、最終的に勝つことができます。そのため、ボブはアリスの左から右(または右から左)に移動し、移動後にアリスに一度も追い込まれないようにする必要があります。
ボブとアリスの間の距離をda以下にすることはできないため、2×\ times× da> = dbの場合、ボブは安全を確保しながらアリスの片側から反対側に移動することができず、アリスが勝つ必要があります。

次に2 ×\ times× da <dbの場合、ボブは安全に左右に移動でき、ボブは無敗を保証できます。

それ以来、すべてのケースが導き出されています。

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=1e5+7;

ll n,a,b,da,db,dis_ab;//dis_ab记录在树上a和b两点之间的距离
ll dis[maxn];//dis[i]记录每次dfs过程中,i点距离起点的距离

struct Edge
{
    
    
    ll to,next;
}edge[maxn<<1];

ll head[maxn],tot;

void init()
{
    
    
    for(ll i=1;i<=n;i++) head[i]=-1;
    tot=0;
}

void add(ll u,ll v)
{
    
    
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
//前向星存图

void dfs(ll now,ll pre,ll deep)
{
    
    
    dis[now]=deep;
    for(ll i=head[now];i!=-1;i=edge[i].next)
    {
    
    
        ll to=edge[i].to;
        if(to!=pre)
        {
    
    
            dfs(to,now,deep+1);
        }
    }
}


int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        cin>>n>>a>>b>>da>>db;
        init();
        for(ll i=1;i<n;i++)
        {
    
    
            ll u,v;
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }

        //两次dfs得到树的直径,第一次dfs的起点可以任意选择,第二次dfs的起点选择第一次dfs过程中距离最远的点
        //两次dfs得到的两个距离最远的点就是树的直径的两个端点,第二次dfs结束后dis[]数组中的最大值就是树的直径大小
        //由于第一次dfs的起点可以任意选择,因此我们选择a为起点,顺带计算出a和b两点间的距离
        dfs(a,-1,0);
        ll tar=1;
        for(ll i=2;i<=n;i++)
            if(dis[i]>dis[tar]) tar=i;

        dis_ab=dis[b];
        dfs(tar,-1,0);
        tar=1;
        for(ll i=2;i<=n;i++)
            if(dis[i]>dis[tar]) tar=i;

        if(dis_ab<=da||2*da>=dis[tar]||da*2>=db) cout<<"Alice"<<endl;
        else cout<<"Bob"<<endl;
    }
}

おすすめ

転載: blog.csdn.net/StandNotAlone/article/details/108474095