A.電話番号
勝利戦略は、前と同じである\(N-- 10 \)は、ビット数の前に存在している(8 \)は\することができます。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 110;
int n;
char s[N];
int main(){
int T; scanf("%d", &T);
while(T--){
scanf("%d%s", &n, s + 1);
bool flag = false;
for(int i = 1; i <= n - 10; i++)
if(s[i] == '8') flag = true;
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
B.ロスト番号
列挙は、暴力に答えます。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int a[6] = {4, 8, 15, 16, 23, 42};
int b[4];
bool inline judge(){
for(int i = 0; i < 4; i++)
if(a[i] * a[i + 1] != b[i]) return false;
return true;
}
int main(){
for(int i = 1; i <= 4; i++){
printf("? %d %d\n", i, i + 1);
fflush(stdout);
scanf("%d", b + i - 1);
}
do{
if(judge()){
printf("! ");
for(int i = 0; i < 6; i++)
printf("%d ", a[i]);
puts("");
fflush(stdout);
break;
}
}while(next_permutation(a, a + 6));
return 0;
}
C.ニュース配信
これは...互いに素セットタイトル、それを裸ではないでしょうか?
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 500010;
int n, m, f[N], size[N];
int inline find(int x){
return f[x] == x ? x : f[x] = find(f[x]);
}
void inline merge(int x, int y){
x = find(x), y = find(y);
if(x == y) return ;
if(size[x] > size[y]) swap(x, y);
f[x] = y; size[y] += size[x];
}
int main(){
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
f[i] = i, size[i] = 1;
}
for(int i = 1; i <= m; i++){
int k, x; scanf("%d", &k);
if(!k) continue;
scanf("%d", &x);
for(int j = 1, y; j < k; j++){
scanf("%d", &y);
merge(x, y);
}
}
for(int i = 1; i <= n; i++)
printf("%d ", size[find(i)]);
return 0;
}
D. Bicolored RBS
変数維持\(DEP \) 、第一層に電流を表す限り、異なるパリティ集合が満たされるように、層の数の最大値(\ \ lceil maxDep / 2 \ rceil \)
#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;
const int N = 200010;
char str[N];
int n, ans[N], dep = 0;
int main(){
scanf("%d%s", &n, str + 1);
for(int i = 1; i <= n; i++){
if(str[i] == '('){
ans[i] = (++dep) & 1;
}else if(str[i] == ')'){
ans[i] = (dep--) & 1;
}
}
for(int i = 1 ;i <= n; i++)
printf("%d", ans[i]);
return 0;
}
E.範囲の削除
\(二-ポインタ\)アルゴリズム。我々は2つのプロパティを見つけます:
もし\((L、R)\ ) 可能で、その後、\((L、R + 1 )、(L、R + 2)...(L、X)\) が可能です。何かが昇順で昇順に削除されますので。
もし\((L、R)\ ) 次に、実行可能ではない( - 1(L、R \ \)は2)...(L、L - )(L、R) は不可能です。明らかに順番に何かを追加したくないので実現可能となっています。
だから、すべてのために\(L(1 <= L <= X-)\) 、我々は最低見つける\(rは\) 、左の点の条件を満たすように\(リットル\)で解答への貢献を\ (R&LT + N - 1 \) 。我々は、この最小の呼び出し\(式中、R \)する\(R_ {min_l} \)
別の性質は、であり、(Lの\)、\、後添加\(min_l R_ {}は\)だけ増加または変化しない、小さくすることができないことができます。まだ公開資格のどちらかの数よりも多くの数の一部を失うする必要があるため。
私たちは、ダブルポインタ演算を使用することができ、これを考えました。私たちは、使用する必要があります(\ O(1))\実現可能な数の追加かどうかを判断するための時間を。
我々が使用することができる\(O(N)\) 4つの配列を前処理時間:
- \(S_Iは\)数が表す\(iは\)第一の配列の位置に登場しました
- \(T_Iが\)数を表します\(私は\)は、アレイの最新の位置に表示されます。
- \(Sx_i \)番号を表し\(iは\)する(X \)\最初の配列位置に登場
- \(TX_I \)の数を表す\(1 \)をする(私は\)\配列の最新の位置に表示されます。
- 左の場合は\(L \)私たちが知りたい場合は、プロセス、そのため\(L - 1 \)に移動し、\(リットル\)が実現可能です。
場合\(送信[1 - 2] <S [L - 1] \)未満である\(L - 1 \)最初の位置の全ての数の\(L - 1 \)左に移動させることができます。
- プロセスの右端のために、それは決定されている\([1、L - 1 ] \) と([R + 1、X] \)\の範囲の数が条件を満たしている、と判断された\((L、R&LT)\) 、条件かどうか:
\(TX_ {1 - 1} <Sx_ {R + 1} \) 全て以下表す\(Lを- 1 \)番号がより大きい\(R + 1 \)条件の数の左側に満たされ、そうでなければ我々はできるようにする必要があります\(R \)の増加を。
プロセスにおいて、我々は最初の最小値を見つけるそのことに注意してください\(R \)のように、\((1、R)\ ) の条件を満たすように、そして次に展開\(1- \)を 1つの工程の間、増加することを余儀なく\(Rは\)、自然などの\(2 \) 。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 1000010, INF = 0x3f3f3f3f;
typedef long long LL;
int n, x, S[N], T[N], Sx[N], Tx[N];
int a[N];
LL ans = 0;
int main(){
memset(S, 0x3f, sizeof S);
scanf("%d%d", &n, &x);
for(int i = 1; i <= n; i++){
scanf("%d", a + i);
if(S[a[i]] == INF) S[a[i]] = i;
T[a[i]] = i;
}
for(int i = 1; i <= x; i++)
Tx[i] = max(Tx[i - 1], T[i]);
Sx[x + 1] = INF;
for(int i = x; i; i--)
Sx[i] = min(Sx[i + 1], S[i]);
int r = x - 1;
while(r && T[r] < Sx[r + 1]) r--;
for(int l = 1; l <= x; l++){
if(l > 2 && S[l - 1] < Tx[l - 2]) break;
while(r <= x && (r < l || Tx[l - 1] > Sx[r + 1]))
r++;
ans += x - r + 1;
}
printf("%lld\n", ans);
return 0;
}