問題レポートA〜EにCF教育ラウンド78(DIV2)ソリューション
A:二つのライバル学生
問題の意味に応じてシミュレートすることができます
#include<bits/stdc++.h> using namespace std; int T; int n, x, a, b; int main() { cin >> T; while(T--) { cin >> n >> x >> a >> b; if(a > b) swap(a, b); while(x != 0) { if(a > 1) x--, a--; else if(a == 1) break; } while(x != 0) { if(b < n) x--, b++; else if(b == n) break; } cout << b - a << endl; } return 0; }
B:魔法のスティック
1,2,3行、特に文の減少を拡大して、循環に限り、他のを実行します。
#include<bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while(T--) { int x, y; cin >>x >> y; if(x >= y) { puts("YES"); continue; } else { if(x == 2 && y != 3) { puts("NO"); continue; } if(x == 3 && y != 3) { puts("NO"); continue; } if(x == 1 && y != 1) { puts("NO"); continue; } } puts("YES"); } return 0; }
C:支配サブアレイ
リニア掃引が再びうまく、実際には、クエリは、同じ距離を2つの要素の最小数であります
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; int a[maxn], T, n, vis[maxn]; int main() { scanf("%d", &T); while(T--) { scanf("%d", &n); int ans = 0x3f3f3f3f; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); vis[i] = 0; } for(int i = 1; i <= n; i++) { int x = a[i]; if(vis[x]) ans = min(i-vis[x], ans); vis[x] = i; } if(ans == 0x3f3f3f3f) puts("-1"); else cout << ans + 1<< endl; } return 0; }
D:もう一つのモンスターキリング問題
ハーフ+貪欲
人生の最初の特別な宣告最高の攻撃の英雄とモンスターの最大値は、確かに終了しないことには十分ではありません。
2人の英雄ならば英雄のために、\((i、j)は\ ) と同じ攻撃は、しかし\(> JS \ IS) 、その後、我々は確かに選択しないでください\(J \)を選択し(私は\)\。
我々は続くので(P \)\並べ替え操作は、接尾辞に続いて\(B(I).S \ ) を表す\(I \) 〜\(N- \)最大耐久値。
ので、モンスターのために、私たちは、ちょうど彼の攻撃よりも主人公大きいにこのモンスターを見つけることができます\(bは\)向けられてきた(P \)\我々はこの英雄の半分を見つけることができるように、行をソート。
主人公の耐久性は、現在の操作をサポートするのに十分でない場合は、現在のサイクルを殺し、新しい日開き、モンスターのために、ほとんどのモンスターの英雄を殺すことができれば我々は、すべてのモンスターを列挙し、最初の日からスタートすべてのモンスター。
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; int T, n, m; int a[maxn]; struct Node{ int p, s; }b[maxn]; bool cmp(Node a, Node b) {return a.p < b.p;} bool cmpp(Node x, int y) {return x.p < y;} int main() { cin >> T; while(T--) { int mx = 0; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); mx = max(mx, a[i]); } scanf("%d", &m); for(int i = 1, x, y; i <= m; i++) { scanf("%d%d", &x, &y); b[i] = {x, y}; } sort(b+1, b+1+m, cmp); if(b[m].p < mx) { puts("-1"); continue; } for(int i = m - 1; i >= 1; i--) b[i].s = max(b[i].s, b[i+1].s); int days = 1; int las = 0; //上一个怪物 int cnt = 0x3f3f3f3f; //从上一个怪物杀到现在的英雄的最小耐力 for(int i = 1; i <= n; i++) { int t = lower_bound(b+1, b+m+1, a[i], cmpp) - b; cnt = min(b[t].s, cnt); if(cnt + las < i) //当前这只怪物杀不掉了 { cnt = b[t].s; days += 1; las = i - 1; } } cout << days << endl; } return 0; }
E:コンテスト
- \(DP \)
- \は、(F(I、1 / 2/3)\) を表し\(I \)最初の数字\(1,2,3 \)最小手オペランドクラスメートを。
- 初期状態のための\(X \)で\(I \)クラスメートの手がある\(A(X)= I \) 。
- ある状態遷移方程式\(F(I、K)=分(F(I、K)、F(I、J)+(K!= A(I + 1)))\) 、\((1 \当量J \ leq3、J \当量のK \当量3)\)
- 説明:以来\(1,2,3 \)単調に手で学生のシーケンス番号、そう\(J \のLeq K \) 。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn], n;
int f[maxn][5];
int main()
{
int n1, n2, n3;
cin >> n1 >> n2 >> n3; n = n1 + n2 + n3;
for(int i = 1, x; i <= n1; i++)
scanf("%d", &x), a[x] = 1;
for(int i = 1, x; i <= n2; i++)
scanf("%d", &x), a[x] = 2;
for(int i = 1, x; i <= n3; i++)
scanf("%d", &x), a[x] = 3;
memset(f, 0x3f, sizeof(f));
f[0][1] = f[0][2] = f[0][3] = 0;
for(int i = 0; i <= n - 1; i++)
for(int j = 1; j <= 3; j++)
for(int k = j; k <= 3; k++)
f[i+1][k] = min(f[i+1][k], f[i][j] + (k != a[i+1]));
cout << min(min(f[n][1], f[n][2]), f[n][3]) << endl;
return 0;
}