Loading

Educational Codeforces Round 123 (Rated for Div. 2)

A

直接按照题意模拟拿钥匙和开门即可……

$\texttt{Code}$
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
void solve(){
    string s;cin>>s;
    int cntr=0,cntb=0,cntg=0;
    rep(i,0,(int)s.size()-1){
        if(s[i]=='r') cntr++;
        if(s[i]=='g') cntg++;
        if(s[i]=='b') cntb++;
        if(s[i]=='R'){
            if(!cntr){cout<<"NO\n";return;}
            cntr--;
        }
        if(s[i]=='G'){
            if(!cntg){cout<<"NO\n";return;}
            cntg--;
        }
        if(s[i]=='B'){
            if(!cntb){cout<<"NO\n";return;}
            cntb--;
        }
    }cout<<"YES\n";
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;for(cin>>T;T--;)
        solve();
    return 0;
}

B

考虑 \(n\le 50\),范围非常小,于是可以用乱搞过。

当然可以考虑一个优美的构造,考虑倒序的排列一定是反斐波那契,然后题目要求构造 \(n\) 个,那我们考虑把这个序列旋转构成的序列刚好有 \(n\) 个,并且除了 \(n=3\) 以外都是合法的。而 \(n=3\) 就直接贺样例就行了。

$\texttt{Code}$
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
void solve(){
    int n;cin>>n;
    if(n==3){
        cout<<"3 2 1\n";
        cout<<"1 3 2\n";
        cout<<"3 1 2\n";
        return;
    }
    per(i,n,1){
        rep(j,0,n-1){
            int cur=i-j;
            if(cur<=0) cur+=n;
            cout<<cur<<' ';
        }cout<<'\n';
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;for(cin>>T;T--;)
        solve();
    return 0;
}

C

考虑记录长度为 \(len\) 的最大子段和是多少。然后贪心地,\(x\ge 0\),所以加上 \(x\) 一定不亏,于是枚举长度,然后每次在前面记录的最大和上加上 \(\min(len,k)*x\),取最大值就好了。这样预处理 \(O(n^2)\),单次求解 \(O(n)\),题目要求 \(k\in[0,n]\),那就 \(O(n^2)\)

$\texttt{Code}$
#include<bits/stdc++.h>
#define int long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
const int MAXN=5e3+10;
int mlen[MAXN],pre[MAXN];
void solve(){
    int n,x,v;
    cin>>n>>x;
    rep(i,0,n) mlen[i]=-INF,pre[i]=0;
    rep(i,1,n) cin>>v,pre[i]=pre[i-1]+v;
    rep(i,1,n) rep(j,i,n)
        mlen[j-i+1]=max(mlen[j-i+1],pre[j]-pre[i-1]);
    rep(k,0,n){
        int ans=0;
        rep(i,1,n)
            ans=max(ans,mlen[i]+min(i,k)*x);
        cout<<ans<<' ';
    }cout<<'\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;for(cin>>T;T--;)
        solve();
    return 0;
}

D

考虑到染色会覆盖非常麻烦,不好计数。所以考虑把操作倒过来计数,这样的话就不会覆盖。

然后考虑对每行每列记录有没有染色,如果都已经染色,那就对最终总方案数不产生贡献(就是会完全被后面覆盖)。否则每次标记以下,然后答案乘上 \(k\) 就行了。

$\texttt{Code}$
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
const int MAXN=2e5+10;
const int MOD=998244353;
int cx[MAXN],cy[MAXN],x[MAXN],y[MAXN];
void solve(){
    int n,m,k,q;
    cin>>n>>m>>k>>q;
    rep(i,1,q) cin>>x[i]>>y[i];
    int nx=0,ny=0,ans=1;
    per(i,q,1){
        if(nx==n||ny==m) break;
        if(!cx[x[i]]&&cy[y[i]])
            ans=1ll*ans*k%MOD,nx++,cx[x[i]]=1;
        else if(cx[x[i]]&&!cy[y[i]])
            ans=1ll*ans*k%MOD,ny++,cy[y[i]]=1;
        else if(!cx[x[i]]&&!cy[y[i]])
            ans=1ll*ans*k%MOD,nx++,ny++,cx[x[i]]=cy[y[i]]=1;
    }rep(i,1,q) cx[x[i]]=cy[y[i]]=0;
    cout<<ans<<'\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;for(cin>>T;T--;)
        solve();
    return 0;
}

E

比 D 简单好多。考虑一个本质贪心,就是说你复制一定是把第一次出现的方向复制,因为你如果不复制第一次出现的,后面的可以用复制第一次出现的来代替。

于是整个的做法就是先求出最终的横纵坐标,这样可以求出 RD 分别至多被复制多少次,然后从前往后扫,到一个位置,并记录前面有没有出现过 R 以及 D,假如说下一步是向下走的,那么当前格子对最终答案贡献是向右走,否则贡献是向下走,然后判断一下贡献应该是 \(1\)(没有出现过向贡献方向走的字符)还是能向贡献方向复制的最多次数 \(+1\)

$\texttt{Code}$
#include<bits/stdc++.h>
#define int long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;
void solve(){
    int n;string s;cin>>n>>s;
    int x=1,y=1,D=0,R=0;
    rep(i,0,(int)s.size()-1){
        if(s[i]=='D') x++,D=1;
        if(s[i]=='R') y++,R=1;
    }
    D=(D?n-x+1:1);R=(R?n-y+1:1);
    int ans=1;
    bool aD=0,aR=0;
    rep(i,0,(int)s.size()-2){
        if(s[i]=='D') aD=1;
        if(s[i]=='R') aR=1;
        if(s[i+1]=='D'){
            if(aR) ans+=R;
            else ans++;
        }
        if(s[i+1]=='R'){
            if(aD) ans+=D;
            else ans++;
        }
    }
    ans+=R*D;
    cout<<ans<<'\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;for(cin>>T;T--;)
        solve();
    return 0;
}

F

posted @ 2022-02-23 10:54  ZCETHAN  阅读(81)  评论(0编辑  收藏  举报