トピックリンク:abc190
A-非常に原始的なゲーム
トピック
- 高橋さんと青木さんはお菓子を食べ、交代でお菓子を食べ、順番にお菓子がないと負けます。
- aはTが所有するキャンディーの数、bはAが所有するキャンディーの数、c = 0はTが最初に食べることを意味し、c = 1はAが最初に食べることを意味します。
- 出力の勝者
- 0≤A、B≤100
アイデア
- 最初に食べるAは、Tが1つ食べたことを意味するので、a + cを許可すると、統合されたTが最初にキャンディーを食べます。
- a> bの場合はTが勝ち、そうでない場合はAが勝ちます。
ACコード
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int a, b, c;
cin >> a >> b >> c;
a += c;
if(a > b) puts("Takahashi");
else puts("Aoki");
return 0;
}
B-マジック3
トピック
- マジシャンファイトモンスター、n種類の呪文、各呪文の持続時間はai、ダメージはbi
- モンスターが耐えられる最短時間はs、最大ダメージはdです。
- 魔術師にモンスターを首尾よく殺すように頼む
- 範囲1≤N≤100、1≤ai≤1e9、1≤bi≤1e9、1≤s≤1e9、1≤d≤1e9
アイデア
- すべての呪文にai <sとbi> dがあるかどうかを調べます
- そして、ここでは操作が使用されます
ACコード
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int n, s, d, flag = 0;
scanf("%d%d%d", &n, &s, &d);
while(n --){
int x, y;
scanf("%d%d", &x, &y);
flag |= (x < s && y > d);
}
if(flag) puts("Yes");
else puts("No");
return 0;
}
C-ボウルと料理
トピック
- n種類の料理、m種類のコロケーションa1、bi、kの個別選択料理があります。
- 誰もがciとdiの2つの選択肢を持っています。選択した後、満足しているコロケーションの数を確認してください
- 最大でいくつの試合が行われるかを尋ねる
- 範囲:2≤N≤100、1≤M≤100、1≤Ai <Bi≤N、1≤K≤16、1≤Ci <Di≤N
アイデア
- 状態圧縮
- 最大で16人しかないため、すべての状況をバイナリで列挙できます。0は最初の料理を選択することを意味し、1は2番目の料理を選択することを意味し、vis配列をマークします。
- 次に、コロケーション(両方が存在する場合はcnt ++)をトラバースし、最後にこのcntの最大値を更新します。
ACコード
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int a[105], b[105], c[105], d[105];
int vis[105];
int main(){
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++){
scanf("%d%d", &a[i], &b[i]);
}
int k; scanf("%d", &k);
for(int i = 0; i < k; i ++){
scanf("%d%d", &c[i], &d[i]);
}
int ans = 0;
for(int t = 0; t < (1 << k); t ++){
for(int i = 1; i <= n; i ++) vis[i] = 0;
for(int i = 0; i < k; i ++){
if((t >> i) & 1) vis[d[i]] = 1;
else vis[c[i]] = 1;
}
int cnt = 0;
for(int i = 1; i <= m; i ++){
if(vis[a[i]] + vis[b[i]] == 2) cnt ++;
}
ans = max(ans, cnt);
}
printf("%d\n", ans);
return 0;
}
D-階段シーケンス
トピック
- nを与えて、いくつの等差数列を形成できるかを尋ねます。許容誤差dは1で、級数の合計はnですか?
- 1≤N≤1e12
アイデア
- 等差数列の合計式はS = n * a0 + n *(n-1)* d / 2です。
- d = 1の場合、Sは項の数nに関連し、最初の項a0、Sは既知であり、nを使用してa0を表します。a0= S / n-(n-1)/ 2-> 2a0 = 2S / n + 1-n
- a0は整数であるため、2S / n + 1-nは偶数であり、nは2Sの因数です。
- O(
)時間を実行して、条件を満たすnの数を見つけます。
ACコード
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
ll n; cin >> n;
int cnt = 0;
n <<= 1;
for(int i = 1; i <= sqrt(n); i ++){
if(n % i == 0){
if((n / i + 1 - i) % 2 == 0) cnt ++;
ll d = n / i;
if(i == d) continue;
if((n / d + 1 - d) % 2 == 0) cnt ++;
}
}
cout << cnt << endl;
return 0;
}
F-シフトと反転
トピック
- 0からn-1までのn個の配列を指定すると、この配列はn-1だけ左に回転します。
- このプロセスでの配列の逆数ペアは何ですか?
- 逆数ペア、i <j、ai> ajを満たすペア<i、j>の数
- 2≤N≤3×1e5
アイデア
- ansの最初の逆順は、ツリー配列またはマージソートで実行されます。これがツリー配列です。
- 次に、たとえば、{2、0、1、3}この左への循環シフトのペアは{0、1、3、2}になります。つまり、2が後方に移動し、2より小さい数は左に移動、逆順a1のペアが少なく、2より大きい数も左に移動し、逆の順序でa2のペアが多くなります。
- これは完全な順列であるため、2より小さい数a1には2ペアがあり、2 a2より大きい数には4-1-2ペアがあります。つまり、ans-a1 + a2のみが必要です。
- 逆順序対の最大値はn *(n-1)/ 2であるため、intが爆発し、longlongを開く必要があります。
ACコード
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) x & -x
const int maxn = 3e5 + 5;
int c[maxn], n;
void add(int x){
for(int i = x; i <= n; i += lowbit(i))
c[i] ++;
}
int query(int x){
int ans = 0;
for(int i = x; i > 0; i -= lowbit(i))
ans += c[i];
return ans;
}
int a[maxn];
int main(){
ll ans = 0; cin >> n;
for(int i = 1; i <= n; i ++){
cin >> a[i]; a[i] ++;
//由于树状数组不能加0,所以a[i]需要加1,那么下面的d1就要对应的+1, d2要对应的-1
add(a[i]);
//query求的是小于等于a[i]的数的个数,i是现在有的个数
//那么现在要求的是逆序对,也就是要求前面比他大的数的个数,那么就是i-query
ans += i - query(a[i]);
}
int d1 = 0, d2 = 0;
for(int i = 1; i <= n; i ++){
cout << ans << endl;
d1 = n - a[i], d2 = a[i] - 1;
ans += d1 - d2;
}
return 0;
}