2023 第 6 回広西チワン族自治区大学生プログラミング コンテスト (公式競技会) 問題解決策

ここに画像の説明を挿入

コンテストのトピックへのリンク、コードの送信を続けることができます: 2023 第 6 回広西大学生プログラミング コンテスト (公式コンテスト)
|
志湖:第 6 回広西大学生プログラミング コンテストをどう評価するか?

困難 質問番号 述べる
チェックインの質問 AJK 与えられた解決策とコード
一般的な質問 BDEH 与えられた解決策とコード
中程度の質問 CG
問題 映画

公式の問題解決策 PPT を入手して、プラットフォーム上の問題コードと chatgpt を組み合わせて説明するチャネルがありません。
間違いがたくさんありますので、修正してください!

チェックインの質問

アルファ、ベータ、オメガ

アルファ、ベータ、オメガ

トピックの主なアイデア:

トランプゲーム。k 枚のカードを引くたびに、α が引かれたら新しい β が投入され、β が引かれたら新しい Ω が投入され、Ω が引かれたらゲームが勝ちとなります。運が最悪の場合、勝つために最大何回引けるかを尋ねてください。

問題解決のアイデア:

一番運が悪いのは、最初にαを引いて、次にβを引いて、最後にΩを引くことです。

実際、αを引いた後にβも同時に引いてしまった場合には対処する必要はありません。

α を描画すると、新しい β が挿入されます。これは、α を 2 回 (α と新しい β) 描画する必要があることを意味します。

(a*2+b)/k+1 を直接実行してください。

参考コード C++

#include <iostream>
using namespace std;
int main()
{
    int a,b,o,k;
    cin>>a>>b>>o>>k;
    if(a+b<k) cout<<1;
    else cout<<((a*2+b)/k+1);
    return 0;
}

J ジューン

J ジューン

トピックの主なアイデア:

2 つの文字列を受け取り、指定どおりに出力します。

問題解決のアイデア:

サブ質問を送信します。

参考コード C++

#include<iostream>
using namespace std;

int main(){
	string s,t;
	cin>>s>>t;
	cout<<"Good luck to "<<s<<" in "<<t<<" and have fun!";
}

Kキーボード

Kキーボード

トピックの主なアイデア:

現在の文字列をその後ろにコピー&ペーストし続け、別の文字列と一致する可能性があるかどうかを尋ねます。

問題解決のアイデア:

実際、最初のコピー アンド ペーストの状況を特に判断する必要はありません。現在の文字列の長さが別の文字列の長さよりも短い限り、ループ内でコピー アンド ペースト自体が行われます。

もちろん、べき乗倍を満たすかどうかを事前に判断することもできますし、実際に判断せずにテストに合格することもできます。

参考コード C++

using namespace std;
string s,t;
 
int main()
{
    cin>>s>>t;
    while(s.size()<t.size())s+=s;
    if(s==t)cout<<"Smart People's Big Win!";
    else cout<<"Lazy Dog's Great Failure...";
    return 0;
}

一般的な質問

B 素晴らしいアイデア

B 素晴らしいアイデア

トピックの主なアイデア:

この質問により、文字列ゲームをプレイすることができます。毎回、部分文字列を選択し、この部分文字列内の文字を部分文字列内の任意の文字に変更できます。ゲームの目標は、できるだけ多くの操作を行うことです。次の 3 つの条件のいずれかを満たす、小文字のみで構成される長さ n の文字列がいくつあるか推測します。

  • 変更によって 2 つの文字の状態に到達することはできません。
  • 限られた数の変更を行うことで、任意の 2 つの異なるキャラクターに到達できます。
  • どれだけ変更を加えても、2 つの文字が異なる状態には到達できません。

問題解決のアイデア:

n=2の特殊な場合は単独で出力することも可能です。
n>2の場合

  • 最初の質問では、隣接する同一文字がない長さ n の文字列がいくつあるかを計算する必要があります。実際には、これらの条件を満たす aa 、 bb … zz の 26 種類しかありません。
  • 2 番目の質問では、有限回数の操作を行った後、指定された文字列に 1 文字しか含めることができないかどうかを判断する必要があります。実際、次の結果の導出は満足のいくものではなく、最初のケースに属するか、3 番目のケース、つまりゼロに属するかのいずれかです。
  • 3 つの質問では、特定の文字列を無限に操作できるかどうかを判断する必要があります。文字列の長さが偶数の場合は、文字列の型を直接構築します。

参考コード C++

#include <iostream>
using namespace std;
long long a,b,c=26ll,sum=1,mod=1e9+7;
int main()
{
	cin>>a;
	if(a==2) cout<<"26 650 0";
	else{
		b=a%mod;
		while(b>0){
			if(b&1) sum=(sum*c)%mod;
			c=(c*c)%mod;
			b>>=1;
		}
		cout<<"26 0 "<<(sum-26+mod)%mod;
	}
	return 0;
}

Dドリームチーム

Dドリームチーム

トピックの主なアイデア:

3n 人を n チームに分け、各チームに 3 人ずつ所属し、全員の不安値の合計が最小になるようにします。人にとって、彼の不安値は、チーム内の知らない人の数に等しくなります。

問題解決のアイデア:

この質問は、和集合検索の同様のアイデアを使用して解決できます。

チーム内の生徒は全員がお互いによく知っているので、生徒の 1 人を代表とみなした場合、その代表がいる接続されたブロックは、チームが拡張できるすべての生徒になります。したがって、どの生徒の不安値も増加させないように、同じ接続されたブロック内のすべての生徒を同じグループに分けることを検討できます。

生徒 u について、和集合検索などを利用して、生徒 u が位置する連結ブロック c_u を見つけ、チーム t ごとに、生徒 v が位置する連結ブロック c_v が c_u と同じであるかどうかを判断します。 tで。このような v が存在する場合、t 内のすべての生徒を u と同じグループに割り当てることができ、チーム t の不安値は 0 になります。そうでない場合は、t 内の各生徒を u とは異なるグループに割り当てる必要があります。 、その不安値は、チーム メンバー内の見慣れない人の数です。

要約すると、各生徒 u を横断して、チーム t ごとに同じグループに割り当てることができるかどうかを判断できます。次に、すべてのチームの不安値を合計すると、これが答えになります。

参考コード C++

#include <iostream>
using namespace std;
int n,m,x,y,a,b,f[3000006],num[3000006];
int fnd(int a){
    return f[a]==a?a:f[a]=fnd(f[a]);
}
int main()
{
	cin>>n>>m;
    n*=3;
	for(int i=1;i<=n;i++) f[i]=i; 
	for(int i=1;i<=m;i++){
		cin>>x>>y;
		int fx=fnd(x),fy=fnd(y);
		if(fx!=fy) f[fx]=fy;
	}
	for(int i=1;i<=n;i++) num[fnd(i)]++;
	for(int i=1;i<=n;i++){
		if(f[i]==i){
			if(num[i]%3==2) a++;
			else if(num[i]%3==1) b++;
		}
	}
	if(a>=b) cout<<b*4+(a-b)/3*8;
	else cout<<(a+b)*2;
	return 0; 
} 

E 悪の資本家

E 悪の資本家

トピックの主なアイデア:

ある会社は n 人の従業員を雇用しており、各従業員の給与は a_i 元です。ある従業員の給与がその下の従業員の給与よりも高い場合、その従業員は不満を感じます。従業員がストライキを起こすのを防ぐために、会社は、2人での会話を数回行って互いの給与を知らせ、不満を持った従業員に対して適切な給与調整を行い、最終的に不満を抱くのは1人の従業員だけになるようにすることができます。他の従業員も満足しています。この目標を達成するために最低限支払う必要がある金額を企業に尋ねてください。

問題解決のアイデア:

この問題は、古典的な貪欲アルゴリズムの問​​題です。まず、すべての従業員を給与の高い順に並べ替え、すべての従業員を不満の状態に初期化します。次に、各従業員を反復処理します。従業員が処理されていない場合は、その従業員より給与が低い最初の従業員を見つけて、次の操作を実行します。

2 人の従業員の給与が同じであれば、どちらも満足します。
下の従業員の賃金が現在の従業員の賃金よりも低ければ、下の従業員は満足し、現在の従業員の賃金は下の従業員の賃金まで上昇します。そして、現在の従業員よりも給与が低い従業員がいなくなるまで下を向き続けます。
この方法ですべての従業員を処理した後、支払う必要がある最終的な合計金額を取得できます。時間計算量は O(nlogn) です。n は従業員の数で、主に仕分け操作に消費されます。

参考コード C++

#include <bits/stdc++.h>
using namespace std;
long long n,sum,mx,cnt,now,a[200007];
int main() {
    cin >> n;
    for(int i=0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    a[n]=2e9+7;
    for(int i=1;i<=n;i++){
        if(a[i]==a[i-1]) cnt++;
        else{
            now=cnt%2?0:a[i]-a[i-1];
            sum+=now;
            mx=max(mx,now);
            cnt = 0;
        }
    }
    cout<<sum-mx;
    return 0;
}

H かくれんぼ

H かくれんぼ

トピックの主なアイデア:

この質問の意味は、正の整数 x (1≤x≤a) と m 個の制約が与えられた場合、各制約は b_j mod x =c_j の形式になるということです。すべての制約を満たすという前提の下で、[1,a] 内のすべての条件を同時に満たす正の整数がいくつあるかを調べます。条件を満たす正の整数が少なくとも 1 つ存在することが保証されます。

問題解決のアイデア:

ループを使用して各制約条件を読み込み、b_j −c_j の最大公約数 gcd を計算し、すべての制約条件を満たす最小の正の整数 l を計算します。

1 から gc の平方根まで、gcd の各因数 i を列挙します。i が要件を満たしている場合は、ans を 1 増やします。gcd/i も要件を満たし、gcd/i が i に等しくない場合は、ans も 1 増やします。最後に、制約を満たす正の整数の数である ans が出力されます。

gcd=0 の場合は、a−l+1 をそのまま出力する必要があります。

参考コード C++

#include<bits/stdc++.h>
using namespace std;
long long m,a,b,c,gc,l=1,ans=0;
int main(){
    cin>>m>>a;
    while(m--){
        cin>>b>>c;
        gc=__gcd(b-c,gc);
        l=max(l,c+1);
    }
    for(int i=1;i<=gc/i;i++){
        if(gc%i==0){
        	if(i<=a&&i>=l)ans++;
            if(gc/i!=i&&gc/i<=a&&gc/i>=l)ans++;
        }
    }
    if(gc==0) cout<<a-l+1;
    else cout<<ans;
}

中程度の質問

まだ調べてないです、うーん


問題

それは私の想像を超えています、うーん、誰かがそれを補ってくれることを願っています


おすすめ

転載: blog.csdn.net/weixin_45940369/article/details/131080477