ディレクトリ
対象となる知識ポイント:思考、貪欲、数学。
ゲームへのリンク:ポータル
A-レベル統計
トピック:ゲームの数と通関手続きの数を時系列で示し、妥当かどうかを判断します。
解決策:隣接する間隔と合計間隔の回数が通関手続きの回数以上で、減少していないことを確認してください。
コードを受け入れる:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int maxp=0,maxc=0;
bool flag=true;
while(n--){
int p,c;
cin>>p>>c;
if(p<maxp||c<maxc||p<c||p-maxp<c-maxc){
flag=false;
}
maxp=max(p,maxp),maxc=max(c,maxc);
}
puts(flag?"YES":"NO");
}
return 0;
}
B-中流階級
トピック:富が特定のしきい値以上の富裕層であることを規定するために、各操作で多数の人々を選択できるため、それぞれの富が平均になります。
問題の解決策:大きいものから小さいものに並べ替えた後に貪欲です。
コードを受け入れる:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll a[maxn];
int main(){
int t;
cin>>t;
while(t--){
int n;
ll x;
cin>>n>>x;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
reverse(a+1,a+1+n);
int cnt=0;
ll sum=0;
for(int i=1;i<=n;i++){
sum+=a[i];
if(sum>=x*i)cnt++;
else break;
}
cout<<cnt<<"\n";
}
return 0;
}
C-モンスターの輪
トピック:モンスターの輪があり、各モンスターのヘルスは\(a_i \)であり、すべてのモンスターヒットは1ヘルスを失い、モンスターが死亡すると、次のモンスターに\(b_i \)ダメージを与えます。すべてのモンスターを破壊するために必要なショット数。
解決策:最初に前のモンスターの死によって引き起こされるであろうダメージまですべての血を修復し、次にモンスターを殺すために最小のダメージを選択します。
コードを受け入れる:回転の使い方を学びました。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e6+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll a[maxn],b[maxn];
int main(){
int t;
cin>>t;
while(t--){
ll n,ans=inf,cnt=0;
scanf("%lld",&n);
for(int i=0;i<n;i++)scanf("%lld%lld",&a[i],&b[i]);
rotate(b,b+n-1,b+n);
for(int i=0;i<n;i++){
if(a[i]>b[i])cnt+=a[i]-b[i];
}
for(int i=0;i<n;i++){
ll res=0;
if(a[i]>b[i])res-=(a[i]-b[i]);
res+=a[i];
ans=min(ans,res);
}
cout<<cnt+ans<<"\n";
}
return 0;
}
D-最小オイラーサイクル
トピック:与えられた\(n \)個の頂点を持つ完全な有向グラフ。最小の辞書式順序でオイラーループの特定の間隔を見つける必要があります。
解決策:タイトルに示されている\(n = 3 \)の例を見ると、\(\ left [1,2,1,3 \ right] \ left [2,3 \ right] \ left [1 \ right ] \)
のためにその手段1(\ \ SIM N \)各ノードについて、辞書式に最小の現在の点から戻ってくるたびに順番に次のノードに移動を開始し、現在のポイントが、移動\(N- \)場合戻ることができない場合は、直接次のノードに移動する必要があります。そうしないと、移動する方法がありません。最後に、1つのノードに戻ります。
観察により、\(1 \ sim n \)ノードの場合、各グループには\(2(ni)\)ノードがあり、奇数番号のノード自体があり、偶数番号のノードが現在のグループにあることがわかります位置は\(2 + i \)で除算されます。
コードを受け入れる:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int t;
cin>>t;
while(t--){
ll n, l, r;
cin>>n>>l>>r;
ll limit = 1ll * n * (n - 1) + 1;
ll sum = 0, id = 1;
for (ll i = l; i <= r && i < limit; i++){
while (sum + (n - id) * 2 < i)
sum += (n - id) * 2, id++;
ll d = i - sum;
printf("%lld ", (d & 1) ? id : d / 2 + id);
}
if (r == limit)
cout<<"1 ";
cout<<"\n";
}
}
E-除数パス
トピック:
正の整数\(D \)が与えられた場合、これを使用して画像を作成します
- 各ノードは\(D \)の因数です
- \(x、y(x> y)\)\(y \)が\(x \)の因数であり、\(\ frac(x)(y)\)が素数の場合、ノード間に無向エッジがあります
- \(X、Y \)右辺間のエッジがある場合\(X \)因子ではない\(Y \)因子の数
、所与の\(Q \)グループ照会要求\(U 、v \)最短パスの数
解決策:まず、いくつかの要因を投げて、ノード\(u \)を別のノード\(v \)に転送するプロセスを考えることができます。ここで、\(v | u \)
はuuからvvです最短パスは\(d(u)-d(x_1)+ d(x_1)-d(x-2)+ \ ldots + d(x_y)-d(v)= d(u)-d(v)\ )、ここで\(d(x)\)は\(x \)の因子の数であるため、ノードがノードで割り切れる場合、2つのノード間の最短経路は2つのノードの因子の数の差になります。\(u \)と\(v \)の関係が倍数ではないことを考えると、ノードの転送はいくつかの要因をスローすることによって実現する必要があるため、\(u- )になるように中間ノード\(x \)を見つける必要があります。> x \)と\(v-> x \)、そして明らかに\(x \)は\(u \)と\(v \)の共通因子でなければならない、最短経路は\(d(u )-d(x)+ d(v)-d(x)\)最小、それから\(d(x)\)を最大にすることなので、\(x = gcd(u、v)\)、最後に請う\(g(u、gcd(u、v))* g(v、gcd(u、v))\)、ここで\(g(u、v)\)は\(u \)と\(v \ ) 2点間の最短経路の数
ノード\(u \)から別のノード\(v \)へのノードは常にいくつかの要素をスローすることによって実行されるため、これらの数はこれらの中間要素のスローです順不同、次に\(g(u、v)\)の場合、ここで\(v | u \)、\(x = \ frac {u} {v} \)、次に\(g(u、v) = \ frac {t!} {p_1!* p_2!... p_n!} \)、ここで\(t \)は\(x \)の素因数のべき乗の合計、\(p_i \)は\ (x \)の素因数のべき乗は、順列と組み合わせにおける反復消去問題の階乗許容コードです
。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
map<ll, ll> m;
ll calc(ll x){
if (m[x])
return m[x];
ll res = 0, y = x;
for (ll i = 2; i * i <= y; i++)
if (y % i == 0){
while (y % i == 0)
y /= i;
res = (res + calc(x / i)) % mod;
}
if (y > 1)
res = (res + calc(x / y)) % mod;
return m[x] = res;
}
int main(){
ll d, q;
cin>>d>>q;
m[1] = 1;
while (q--){
ll u, v;
cin>>u>>v;
ll w = __gcd(u, v);
printf("%lld\n", calc(u / w) * calc(v / w) % mod);
}
return 0;
}