C. A TRUE Battle
如果开头和结尾有 $1$,那么一定 Alice 胜
如果中间有相邻的两个 $1$,那么 Alice 可以先选这俩中间 Or 再任选一边 Or 最后一定胜
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <bits/stdc++.h>
using namespace std;
void solve(){
int n;
string s;
cin>>s;
if(s[0]=='1'||s[n-1]=='1')cout<<"YES\n";
for(int i=0;i<n;i++){
if((s[i]-'0')&&(s[i+1]-'0')==1){
cout<<"YES\n";
return;
}
}
cout<<"NO\n";
}
int main(){
int t;
cin>>t;
while(t--)solve();
}
|
D. QED’s Favorite Permutation
观察题目发现,除非出现 $LR$ 这样的片段,不然就会形成一个片段,这个片段中的每个元素都可以互换位置。
那么就可以判断每个片段中是否有不属于这个片段的元素存在,如果有即为 NO,反之为 YES
开一 $cnt$ 数组来记录位置错乱的值,如果前缀和 $cnt=0$ 那么当前片段即为可行片段
如果出现了 $LR$ 同时 $cnt!=0$ 那么答案就为 NO
只需要实时更新不合法的位置即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#include <bits/stdc++.h>
using namespace std;
#define ls now<<1
#define rs now<<1|1
#define endl "\n"
#define lowbit(x) ((x)&(-x))
typedef long long ll;
const int N=2e5+7, mod=1e9+7;
int n,q;
int p[N],cnt[N];
string s;
set<int>st;
void solve(){
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>p[i];
for(int i=1;i<=n;i++){
cnt[min(i,p[i])]++;
cnt[max(i,p[i])]--;
}
for(int i=2;i<=n;i++)cnt[i]+=cnt[i-1];
cin>>s;
s=" "+s;
for(int i=1;i<n;i++){
if(s[i]=='L'&&s[i+1]=='R'&&cnt[i])st.insert(i);
}
while(q--){
int x;
cin>>x;
s[x]=(s[x]=='L'?'R':'L');
if(s[x-1]=='L'&&s[x]=='R'&&cnt[x-1])st.insert(x-1);
else st.erase(x-1);
if(s[x]=='L'&&s[x+1]=='R'&&cnt[x])st.insert(x);
else st.erase(x);
if(!st.empty())cout<<"NO\n";
else cout<<"YES\n";
}
st.clear();
memset(cnt,0,sizeof(cnt));
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
return 0;
}
|
有点类似的两道题
CF Round 977
C1. Adjust The Presentation (Easy Version)
初始序列的某个成员,他在播放序列中出现的顺序一定比他后面的人前,不可能在播放序列中出现倒序的情况
相当与只考虑实际初始序列中的相邻位置,如果上一个人没有播放过,或者他播放的顺序比后面那个晚,那一定不可能达成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
#include <bits/stdc++.h>
using namespace std;
#define ls now<<1
#define rs now<<1|1
#define endl "\n"
#define lowbit(x) ((x)&(-x))
typedef long long ll;
const int N=2e5+7, mod=1e9+7;
int n,m,q;
int a[N],b[N],c[N];
void solve(){
cin>>n>>m>>q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>b[i];
memset(c,0x3f3f3f,sizeof(c));
for(int i=1;i<=m;i++){
if(c[b[i]]>N)c[b[i]]=i;
}
for(int i=2;i<=n;i++){
int now=a[i],lst=a[i-1];
if(c[now]<N&&c[lst]>N||c[now]<c[lst]){
cout<<"TIDAK\n";
return;
}
}
cout<<"YA\n";
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
return 0;
}
|
C2. Adjust The Presentation (Hard Version)
与 C1 相比,加了 Q 次可持久化更改和询问
实际思路仍和上题相似
我们可以维护不合法的所有位置,即初始序列中那些相邻的前者未播放,或后者先于前者在播放序列出现的组合
将所有的不合法组合储存起来,每次更新检查剩下的组合是否为 0,如果为 0 即总序列为合法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
#include <bits/stdc++.h>
using namespace std;
#define ls now<<1
#define rs now<<1|1
#define endl "\n"
#define lowbit(x) ((x)&(-x))
typedef long long ll;
const int N=1e6+7, mod=1e9+7;
const ll inf=1e16;
int n,m,q;
int a[N],b[N],c[N],d[N];
set<int>s[N];
int check(int x){
int cnt=0,l=a[x-1],r=a[x+1],now=a[x];
if(x<n&&d[now]>d[r])cnt++;
if(x>1&&d[l]>d[now])cnt++;
return cnt;
}
void solve(){
memset(c, 0, sizeof(c));
cin >> n >> m >> q;
for(int i = 1; i <= n; i++){
cin >> a[i];
s[i].clear();
c[a[i]] = i;
d[i] = inf;
}
for(int i = 1; i <= m; i++){
cin >> b[i];
s[b[i]].insert(i);
}
for(int i = m; i > 0; i--) d[b[i]] = i;
int cnt = 0;
for(int i = 1; i < n; i++){
if(d[a[i]] > d[a[i + 1]]) cnt++;
}
if(!cnt) cout << "YA\n";
else cout << "TIDAK\n";
while(q--){
int x, y;
cin >> x >> y;
s[b[x]].erase(x);
s[y].insert(x);
for(int i:{b[x],y}){
cnt-=check(c[i]);
if(s[i].empty())d[i]=inf;
else d[i]=*s[i].begin();
cnt+=check(c[i]);
}
b[x]=y;
if(!cnt)cout<<"YA\n";
else cout<<"TIDAK\n";
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)solve();
return 0;
}
|