Codeforces Round 979 (Div. 2)

Codeforces Round 979 (Div. 2) 总结

A

首先第一位的贡献一定是 \(0\),然后考虑接下来 \(n-1\) 位,我们可以把最大值和最小值放在第一位和第二位,这样贡献就是 \((max-min) \times (n-1)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=1005;
int n;
void solve()
{
    int mx=0,mi=N;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        mx=max(mx,x);
        mi=min(mi,x);
    }
    cout<<(mx-mi)*(n-1)<<'\n';
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

B

因为不同位置的 \(1\)\(0\) 组成的子序列算作不同的,观察可知,当只有一个 \(1\) 时最小,为 \(1\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
int n;
void solve()
{
    cin>>n;
    cout<<1;
    for(int i=1;i<n;i++) cout<<0;
    cout<<'\n';
}
int main ()
{
    #ifndef ONLINE_JUDGE 
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

C

充分理解下题意,当 \(1\) 的左右都是 \(0\) 时,才能用 \(and\) 操作消掉 \(1\)。所以如果开头或结尾是 \(1\),或者有连续的两个 \(1\),输出 YES

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=2e5+5;
int n;
string s;

void solve()
{
    cin>>n>>s;
    s="0"+s;
    int st=0;
    if(s[1]=='1'||s[n]=='1') st=1;
    for(int i=1;i<n;i++) if(s[i]=='1'&&s[i+1]=='1') st=1;
    if(st) puts("YES");
    else puts("NO");
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

D

首先 \(\texttt{L}\)\(\texttt{R}\) 相当于左移和右移,以及我们只需要考虑右移(或左移)即可。

对于每个形如 \(\texttt{RRR} \dots \texttt{LLL} \dots\) 的子串 \([l,r]\),其中的 \(p_i\)(\(l \le i \le r\)) 显然可以到达 \([l,r]\) 中的任一位置,也就是说我们可以任意安排 \([l,r]\) 的顺序。
可知 \(s\) 由多个上述子串构成。

而对于 \(1 \le i < n\),若 \(s_i=\texttt{L}\)\(s_{i+1}=\texttt{R}\),都会在 \(i\) 处形成一个断点。也就是说 \([1,i]\) 中的数都不可能右移到 \([i+1,n]\) 的位置。因为只考虑右移,我们只考虑最大值,序列要合法就必须所有的 \([l,r]\) 的最大值小于等于 \(r\)

因此我们考虑每个 \(\texttt{L} \texttt{R}\),下标为 \(i\)\(i+1\),如果 \([1,i]\) 的最大值大于 \(i\),就说明不可以实现。统计这样不合法的 \(\texttt{L} \texttt{R}\) 的个数 \(cnt\),等于 \(0\) 输出 YES

最后思考修改后会有什么影响,就是看看改之前和改之后是不是 \(\texttt{L} \texttt{R}\),更新 \(cnt\) 即可。

只需要求前缀最大值就行。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,q;
int a[N],b[N];
string s;
void solve()
{
    cin>>n>>q;
    for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i];
    for(int i=1;i<=n;i++) b[i]=max(b[i-1],b[i]);
    cin>>s;
    s='0'+s;
    int cnt=0;
    for(int i=2;i<n;i++)
        if(s[i]=='L'&&s[i+1]=='R') 
            if(b[i]>i)
                cnt++;
    while(q--)
    {
        int x;
        cin>>x;
        if(s[x]=='L')
        {
            s[x]='R';
            if(s[x+1]=='R') if(b[x]>x) cnt--;
            if(s[x-1]=='L') if(b[x-1]>x-1) cnt++;
        }
        else 
        {
            s[x]='L';
            if(s[x-1]=='L') if(b[x-1]>x-1) cnt--;
            if(s[x+1]=='R') if(b[x]>x) cnt++;
        }
        if(!cnt) puts("YES");
        else puts("NO");
    }
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}


posted @ 2024-10-21 14:46  zhouruoheng  阅读(25)  评论(0编辑  收藏  举报