Codeforces Round #744 (Div. 3)


A. Casimir’s String Solitaire

题意:
给你一个只含 A , B , C A,B,C A,B,C字符串 s s s, 每次可以删除一个 A A A和一个 B B B,或者删除一个 A A A和一个 C C C,问
是否能把 s s s删为空串

思路:
统计 A , B , C A,B,C A,B,C的数量即可, c n t A + c n t C = c n t B cnt_A+cnt_C=cnt_B cntA+cntC=cntB即为 Y E S YES YES

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define int ll
#define mst(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define pb emplace_back
#define mp make_pair
#define endl '\n'
#define fi first
#define se second
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
mt19937 rnd(time(0));
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=1,M=2*N;
 
 
void solve(){
    string s;
    cin>>s;
    int a=0,b=0,cc=0;
    if(SZ(s)&1){
        cout<<"NO\n";
        return;
    }
    for(auto c:s)
        if(c=='A') a++;
        else if(c=='B') b++;
        else if(c=='C') cc++;
    if(b==a+cc) cout<<"YES\n";
    else cout<<"NO\n";
}
 
signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}

B. Shifting Sort

题意:给你一个长度为 n n n的数组 a a a,每次可以选择一个区间 a l ∼ a r a_l \sim a_r alar,并且把这段区间 a l ∼ a l + d − 1 a_l\sim a_{l+d-1} alal+d1,移到数组的最右端, a l ∼ a r → a l + d ∼ a r , a l ∼ a l + d + 1 a_l\sim a_r \to a_{l+d} \sim a_r,a_l\sim a_{l+d+1} alaral+dar,alal+d+1,问你是否可以通过少于 n n n次的操作,使得数组有序

思路:
a a a元素做一个 1 ∼ n 1\sim n 1n的映射,每一次找到最小值的下表,把最小值的下标之前的区间 r o t a t e rotate rotate到数组右端, r o t a t e ( l , r + 1 , n + 1 ) rotate(l,r+1,n+1) rotate(l,r+1,n+1),表示将一个长度为 n n n的数组 l ∼ r l\sim r lr 放在数组右端

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define debug(x) cout<<#x<<"="<<x<<endl;
#define ll long long
#define int ll
#define mst(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define endl '\n'
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
mt19937 rnd(time(0));
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=100,M=2*N;

int n;
int a[N],pos[N];
vector<PII> save,ans;

void solve(){
    save.clear();
    ans.clear();
    cin>>n;
    rep(i,1,n){
        int x;cin>>x;
        save.push_back({x,i});
    }
    sort(ALL(save));
    rep(i,0,SZ(save)-1){
        auto it=save[i];
        a[it.second]=i+1;
    }
    rep(i,1,n) pos[a[i]]=i;
    

    rep(i,1,n){
        if(i==a[i]) continue;
        ans.push_back({i,pos[i]-i});
        rotate(a+i,a+pos[i],a+1+n);
        //rep(j,1,n) cout<<a[j]<<' ';
        //cout<<endl;
        rep(j,i+1,n) pos[a[j]]=j;
    }

    cout<<SZ(ans)<<endl;
    for(auto it:ans){
        cout<<it.first<<' '<<n<<' '<<it.second<<endl;
    }
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}

C. Ticks

题意:
给你一个只含 ∗ * . . . n ∗ m n*m nm的矩阵,检查它是否能有若干个长度至少为 k k k的对勾画成

思路:设定一个全为 . . .的数组 a n s ans ans,遍历每一个位置,分别像左上和右上延伸,如果延申的长度大于等于 k k k,则把 a n s ans ans的这些位置都画成 ∗ * ,最后比对 a n s ans ans是否和原矩阵相同

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define debug(x) cout<<#x<<"="<<x<<endl;
#define ll long long
#define int ll
#define mst(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define endl '\n'
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
mt19937 rnd(time(0));
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=50,M=2*N;

int n,m,k;
char g[N][N],ans[N][N];

void pr(int x,int y){
    int cnt=0;
    while(x-cnt>=1&&y-cnt>=1&&y+cnt<=m&&g[x-cnt][y-cnt]=='*'&&g[x-cnt][y+cnt]=='*') cnt++;
    if(cnt-1>=k){
        rep(i,0,cnt-1){
            ans[x-i][y-i]='*';
            ans[x-i][y+i]='*';
        }
    }
}

void solve(){
    cin>>n>>m>>k;
    rep(i,1,n) rep(j,1,m){
        cin>>g[i][j];
        ans[i][j]='.';
    }
    
    rep(i,1,n) rep(j,1,m){
        if(g[i][j]=='*') pr(i,j);
    }

    rep(i,1,n){
        rep(j,1,m)
            if(ans[i][j]!=g[i][j]){
                cout<<"NO\n";
                return;
            } 
    }

    cout<<"YES\n";
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}

D. Productive Meeting

题意:
n n n个数,每次任意取出两个数都减一,如果数为 0 0 0就不能选择了,问如何取数使得减的次数最多

思路:
贪心取最大和次大的两个数各减一,用一个堆来维护

AC代码:

#include <bits/stdc++.h>
#include <ostream>
#include <queue>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define debug(x) cout<<#x<<"="<<x<<endl;
#define ll long long
#define int ll
#define mst(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define endl '\n'
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
mt19937 rnd(time(0));
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=2e5+10,M=2*N;

int n;
priority_queue<PII> heap;
vector<PII> ans;

void solve(){
    while(SZ(heap)) heap.pop();
    ans.clear();
    cin>>n;
    rep(i,1,n){
        int x;
        cin>>x;
        heap.push({x,i});
    }    
    
    while(SZ(heap)>=2){
        auto t1=heap.top();
        heap.pop();
        auto t2=heap.top();
        heap.pop();
        if(t1.first>=1&&t2.first>=1) ans.push_back({t1.second,t2.second});
        if(t1.first>=1) heap.push({t1.first-1,t1.second});
        if(t2.first>=1) heap.push({t2.first-1,t2.second});
    }


    cout<<SZ(ans)<<endl;
    for(auto t:ans) cout<<t.first<<' '<<t.second<<endl;
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}

E1. Permutation Minimization by Deque

题意:
给你一个长度为 n n n的数组,问从头开始插入一个 d e q u e deque deque的最小字典序方案

思路:
贪心每次如果大于队头,则放在队尾,否则放在队首

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define int ll
#define mst(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define pb emplace_back
#define mp make_pair
#define endl '\n'
#define fi first
#define se second
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
mt19937 rnd(time(0));
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=2e5+10,M=2*N;

int n;
int a[N];

void solve(){
    cin>>n;
    rep(i,1,n) cin>>a[i];
    deque<int> D;
    D.push_back(a[1]);
    rep(i,2,n){
        if(a[i]>D.front()) D.push_back(a[i]);
        else D.push_front(a[i]);
    }
    while(SZ(D)){
        cout<<D.front()<<' ';
        D.pop_front();
    }
    cout<<endl;
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}

E2. Array Optimization by Deque

题意:
给你一个长度为 n n n的数组,问从头开始插入一个 d e q u e deque deque的得到最少逆序对

思路:
树状数组+离散化
每次插入一个数时,查询数组中 1 ∼ g e t i d ( x ) 1\sim getid(x) 1getid(x)(放队首的逆序对数量)和 g e t i d ( x + 1 ) ∼ n getid(x+1)\sim n getid(x+1)n(放队尾的逆序对数量)的个数,答案加上两者的最小值,并且把 g e t i d ( x ) getid(x) getid(x)数量 + 1 +1 +1

AC代码:

#include <bits/stdc++.h>
#include <algorithm>
#include <limits>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define debug(x) cout<<#x<<"="<<x<<endl;
#define ll long long
#define int ll
#define mst(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define endl '\n'
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
mt19937 rnd(time(0));
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=2e5+10,M=2*N;

int n;
int a[N];

int tr[N];

inline int lowbit(int x) {return x&-x;}

void add(int x,int v)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;
}

int query(int x)
{
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}

VI num;

int getid(int x){
    return lower_bound(ALL(num),x)-num.begin()+1;
}

void solve(){
    num.clear();
    rep(i,1,n) tr[i]=0;
    cin>>n;
    rep(i,1,n){
        cin>>a[i];
        num.push_back(a[i]);
    }

    sort(ALL(num));
    num.erase(unique(ALL(num)),num.end());

    int ans=0;
    rep(i,1,n){
        int t=getid(a[i]);
        int x=query(t-1),y=query(n)-query(t);
        ans+=min(x,y);
        add(t,1);
    }

    cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}

F. Array Stabilization (AND version)

题意:
给定一个只含 0 , 1 0,1 0,1的数组 a 0 … a n − 1 a_0 \dots a_{n-1} a0an1,给定一个操作,把数组右端 d d d个元素移动到数组的左端,然后 & \& &上未操作之前的数组,问把 a a a全变为 0 0 0,最少要操作多少布

思路:
图论+bfs
转化成图论问题,要使数组全为 0 0 0,就是 0 0 0的位置经过若干次操作覆盖了全部位置, d i s t [ x ] dist[x] dist[x]表示 0 0 0的位置到 x x x的最短路,bfs每个为 0 0 0的位置,每步从 p o s → ( p o s + n − d ) % n pos\to (pos+n-d)\%n pos(pos+nd)%n,答案为 d i s t [ 0 ∼ n − 1 ] dist[0 \sim n-1] dist[0n1]的最大值,即可满足全部位置

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define debug(x) cout<<#x<<"="<<x<<endl;
#define ll long long
#define int ll
#define mst(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define endl '\n'
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
mt19937 rnd(time(0));
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=1e6+10,M=2*N;

int n,d;
int dist[N];
queue<int> Q;


void solve(){
    while(SZ(Q)) Q.pop();
    cin>>n>>d;
    rep(i,0,n-1) dist[i]=inf; 
    rep(i,0,n-1){
        int x;cin>>x;
        if(!x){
            dist[i]=0;
            Q.push(i);
        }
    }

    while(SZ(Q)){
        int t=Q.front();
        Q.pop();
        if(dist[t]+1<dist[(t+n-d)%n]){
            dist[(t+n-d)%n]=dist[t]+1;
            Q.push((t+n-d)%n);
        }
    }

    int ans=0;
    rep(i,0,n-1) ans=max(ans,dist[i]);
    if(ans==inf) cout<<"-1\n";
    else cout<<ans<<endl; 
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值