Codeforces Round#671(Div。2)AE問題解決策

Codeforces Round#671(Div。2)AE問題解決策
//評価値1987/2184で記述
//このゲームのADは実際の水です...

コンテストリンク:https://codeforces.ml/contest

質問A
水の質問

タイトルは、長さnの数が与えられた場合、2人が交互にこの数字の特定の数字をマークすることを意味します。最初の手は奇数桁の数字だけをマークでき、2番目の手は偶数桁の数字だけをマークできます。マークされていない位置が1つしかない場合、番号が奇数の場合は最初の手が勝ち、番号が偶数の場合は2番目の手が勝ちます。

この質問では、2人がマークできる数値は互いにまったく無関係です。最後の残りの数が奇数位置にあるか偶数位置にあるかは、nのパリティによってのみ決定されます。最後の残りの数字が奇数の場合、最初のプレーヤーは必ず勝ちたいと思うので、奇数のいずれかが奇数の場合、最後までこの数字を保存する限り、彼は勝利を保証することができます。 。
最後の残りが偶数桁の場合も同様です。

#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;
        string s;
        cin>>s;
        bool flag;
        if(n&1)//如果总数量是奇数的话,奇数位上的数比偶数位上多1个,最后剩下的那个数一定是奇数位上的数
        {
    
    
            flag=0;
            for(int i=0;i<n;i+=2)//只要奇数位上的数存在任何一个是奇数,先手的人都可以使得它成为最后一个数,使得自己获胜
                if(s[i]%2) flag=1;
        }
        else//对应总数量是偶数的情况,最后剩下的数一定是偶数位上的数
        {
    
    
            flag=1;
            for(int i=1;i<n;i+=2)//只要偶数位上的数存在任何一个是偶数,后手的人都可以使得它成为最后一个数,使得自己获胜
                if(s[i]%2==0) flag=0;
        }
        if(flag) cout<<1<<endl;
        else cout<<2<<endl;
    }
}

質問B
単純なルールの要約

問題は、x正方形の正方形が与えられた場合、できるだけ多くの異なる完全なステップを構築する必要があることを意味します。nステップの完全なステップの定義は、各列の左から右への正方形の数が1-nであり、このステップをn個の正方形の部分に分割できることです。

実際、そのような完璧なステップは軸対称の図である必要があると考えるのは簡単であり、絵を描くことは結論の理解と描画に役立ちます。
まず、1階の階段だけが完璧で、2階の階段は完璧ではありません。
3階建ての階段の左下と右上は完全な階段で埋めることができ、残りの部分は正確に正方形です。
7階の左下と右上は3つの完全な階段で埋めることができ、残りの部分は正確に正方形です。

小から大への完全なステップ数の漸化式はf(n + 1)= f(n)×\ timesであると結論付けることができます× f(n)+1

サンプルの最後のデータは、回答が30だけの場合に最大のx値1e18を示しているため、直接的な暴力サイクルで十分です。

#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;

ll num[70];

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        ll x;
        cin>>x;
        ll ans=0,cas=1;
        while(x>0)
        {
    
    
            x-=(1+cas)*cas/2;
            if(x>=0) ans++;
            cas=cas*2+1;
        }
        cout<<ans<<endl;
    }
}

質問C
貪欲、機密扱いのディスカッション

タイトルは、codeforcesのWebサイトでウイルスが蔓延していることを意味し、同じ格付けを持つ人々の間で蔓延します。最初は1人だけが感染していて、評価値はxで、ゲームに参加できませんでした(評価を変更できません)。これで、n人の個人がそれぞれ初期評価を持っています。ゲームに参加するたびに評価を変更できますが、すべての評価変更の合計は0でなければなりません。次に、全員をウイルスに感染させるために必要なマッチ数を尋ねます。

まず、初期評価がxに等しい人の数を分類し、初期評価がxに等しい人をcasとして設定します。
cas = nの場合、最初は全員が感染していて、直接0を出力することを意味します。
cas <nでcas> 0の場合は、最初に感染した人もいなかった人もいます。1回のゲームで感染者の評価値をすべてxにでき、変更値の合計が0の場合、最初に感染した人に対応する変数が直接追加されます。 。したがって、この時点では直接1が出力されます。
cas = 0の場合、最初は誰も感染していないことを意味し、以前の状況の戦略を採用できません。
この時点で、n人の評価の合計を数えます。sumがnを除算でき、sum / n = xである場合、1つのゲームに合格することで、全員の評価をxに変更できます。
また、sum / n!= xまたはsumでnを除算できない場合、1回の試合で全員に感染することはできませんが、1回の試合で1人の感染者を作成し、上記の0 <cas < nの戦略は、合計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;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n,x;
        cin>>n>>x;
        int sum=0,cas=0;
        for(int i=0;i<n;i++)
        {
    
    
            int temp;
            cin>>temp;
            if(temp!=x) sum+=temp;
            else cas++;
        }
        if(cas==n) cout<<0<<endl;
        else if(cas) cout<<1<<endl;
        else
        {
    
    
            if(sum%n==0&&sum/n==x) cout<<1<<endl;
            else cout<<2<<endl;
        }
    }
}

D1 + D2の質問
貪欲、構造

質問はn個の数字を与えることを意味し、それらをシャッフルする必要があります。自分の左右に隣接する数よりも小さい数をできるだけ多く(添え字1と添え字nの数は数えません。つまり、最初と最後の数は数えません)、最大の満足度を出力しますデジタル量、満足のいく工法を出力します。

ここでは、奇数の添え字(添え字は0から始まります)に対して小さな数を作成するために貪欲な戦略を採用し、大きな数を作成するために添え字も作成します。
これは、左と右の境界の数が数えられないため、つまり、添え字0は数えられないため、添え字1から始まる十分な数を構成できます。また、x [1] <x [2]の場合、x [2]は十分な数であってはなりません。つまり、私たちの最適条件も、数値構造によって満たされる数値で区切る必要があります。つまり、奇数の添え字は比較的小さな数を構成し、偶数の添え字は比較的大きな数を構成する必要があります。
元の数値を直接並べ替えた後、下付き文字を左から右に配置し、奇数の下付き文字を小さい順に並べ、次に、下付き文字を左から右に偶数の下付き文字に配置します。このようにして、1。偶数の添え字が最大の添え字であり、2。偶数の添え字の最小値が奇数の添え字の最大値以上であることを確認します。3.偶数番号の添え字の比較的小さい番号が奇数番号の添え字の比較的小さい番号に隣接するようにします。
以上の3点から、そのような欲望が最適な戦略であると結論付けることができる。

D1とD2の違いは、D1の数が異なるため、条件を満たす数の数は(n-1)/ 2であり、D2の数は同じである可能性があるため、詳細をもう一度確認する必要があります。条件を満たすのは数だけです。施工方法は全く同じです。

#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;

vector<ll>num;
vector<ll>out;
ll n;

int32_t main()
{
    
    
    IOS;
    cin>>n;
    num.resize(n);
    out.resize(n);
    for(auto &x:num) cin>>x;
    sort(num.begin(),num.end());
    ll tar=0;
    for(ll i=1;i<n;i+=2) out[i]=num[tar++];
    for(ll i=0;i<n;i+=2) out[i]=num[tar++];
    ll ans=0;
    for(ll i=1;i<n;i+=2) if(i+1<n&&out[i-1]>out[i]&&out[i+1]>out[i]) ans++;
    cout<<ans<<endl;
    for(ll i=0;i<n;i++)
    {
    
    
        if(i) cout<<' ';
        cout<<out[i];
    }
    cout<<endl;
}

質問E
数論、複雑性分析、構造

質問は、数値nが与えられた場合、1を除くすべてのnの因子をリングに配置する必要があり、2つの隣接する位置間の相互素数の対数を最小にする必要があることを意味します。構築スキームを出力し、最小の比較的素数の対数を出力します。

ここで、nのすべての因子は、nの素因数の異なるべき乗を組み合わせることによって得られると考えるのは簡単です。次に、2つの素因数aとbに気づきました。aとbの間にaとbの両方を割り切れる数値cを入れると、a、c、bになります。次に、aとcの間に、aを除算できるすべての因子を配置できます。cとbの間に、bを除算できるすべての因子を配置できます。
これから、最初にnのすべての異なる素因数を見つけ、次に2つの隣接する素因数のnをそれらの間に割る因数を置くことができます。次に、他のすべての数は少なくともこれらの素因数でなければなりません。要素の1つは分割可能です。つまり、前の段落で説明したように、間隔に挿入できます。

次のことは、このスキームが常に実現可能であるかどうかを考えることです。
これらの素因数の場合、2つの素因数の積もnの因数でなければならず、異なる素因数の間で得られた積は等しくてはならないため、隣接する素因数の間にそれらの積を挿入できます。建設計画。しかし、このスキームでは、n = a ×\ times× bは真ではありません。現時点でnにはa、b、nの3つの要素しかないため、上記のスキームに従って、a、n、b、nに構成されます。nを2回繰り返しました。現時点では、実際にはa、n、bしか作成できないため、隣接する素数のペアが存在します。このとき、a、n、b、endl、1、endlを直接出力できます。したがって、nはa×\ timesに正確に等しいと判断します。× b。
しかし、これは10番目の時点で行われます。素因数が2つしかない場合は、隣接する素数の0ペアを作成できますが、×\ timesを2使用します。× b。

ここでの質問はすべてのnの因子の数が2e5以下であることを示しているため、現時点では複雑さを分析する必要があります。因子は素因数の異なるべき乗で構成されるため、素因数の数を取得するのは簡単です。小さい値は1e3を超えないため、より激しいソリューションをとることができます。

n = a ×\ timesを除外× bこれは、隣接する素数のペアを構築する必要がある場合ですが、それ以外の場合、それらを分割できる隣接する素数の間の数の選択は、nのすべての因数で直接見つけることができます。

上記。

#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=31630;

vector<ll>prime;//线性筛筛出sqrt(1e9)内的所有素数
bool v[maxn];

void primes()
{
    
    
    for(ll i=2;i<maxn;i++)
    {
    
    
        if(!v[i])
        {
    
    
            v[i]=1;
            prime.push_back(i);
        }
        for(ll j=0;prime[j]<maxn/i;j++)
        {
    
    
            v[prime[j]*i]=1;
            if(i%prime[j]==0) break;
        }
    }
}


int32_t main()
{
    
    
    IOS;
    primes();
    int t;
    cin>>t;
    while(t--)
    {
    
    
        ll n;
        cin>>n;
        vector<ll>primes_now;//保存当前的n分解质因数后有几个不同的质因子
        ll temp=n;
        for(ll i=0;i<prime.size()&&prime[i]<=temp/prime[i];i++)
        {
    
    
            if(temp%prime[i]==0)
            {
    
    
                primes_now.push_back(prime[i]);
                while(temp%prime[i]==0) temp/=prime[i];
            }
        }
        if(temp>1) primes_now.push_back(temp);

        unordered_map<ll,bool>M;//保存n除了1外的因子有哪些,记录它是否被使用过
        for(ll i=2;i<=n/i;i++)
        {
    
    
            if(n%i==0)
            {
    
    
                M[i]=0;
                M[n/i]=0;
            }
        }
        M[n]=0;


        if(primes_now.size()==2&&primes_now[0]*primes_now[1]==n) cout<<primes_now[0]<<' '<<primes_now[1]<<' '<<n<<endl<<1<<endl;
        //如果n刚好能拆分成两个质因子相乘,就是唯一一种特殊的情况,我们无法构造出0对相邻互质而只能构成1对相邻互质的特殊情况,直接输出三个数字和对数1。
        else
        {
    
    
            vector<ll>mid(primes_now.size());//mid[i]当前n分解的质因子,第i个和第i+1个中间插入的数是哪一个
            for(ll i=0;i<primes_now.size();i++)//直接暴力for一遍,质因子数量是很少的
            {
    
    
                for(auto &x:M)//去n的所有因数里面找既能整除第i个质因子又能整除第i+1个质因子的数
                {
    
    
                    if(!x.second&&x.first%primes_now[i]==0&&x.first&&x.first%primes_now[(i+1)%primes_now.size()]==0)
                    {
    
    
                        mid[i]=x.first;
                        x.second=1;
                        break;
                    }
                }
                M[primes_now[i]]=1;
            }

            for(ll i=0;i<primes_now.size();i++)//然后把剩下没使用过的数字继续暴力放到第i个质因子和mid[i]中间,只需要满足整除第i个质因子即可
            {
    
    
                cout<<primes_now[i]<<' ';
                for(auto &x:M)
                {
    
    
                    if(!x.second&&x.first%primes_now[i]==0)
                    {
    
    
                        cout<<x.first<<' ';
                        x.second=1;
                    }
                }
                cout<<mid[i]<<' ';
            }
            cout<<endl<<0<<endl;
        }
    }
}

おすすめ

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