CF1287 div2题解

前言

昨夜打CF div2,思涨分之事。然脑未上线,BC题皆挂,仅A两道。
特写此篇,以记此耻。

所有题题面:https://codeforces.com/contest/1287/problems

A. Angry Students

题面:https://codeforces.com/contest/1287/problem/A
题解:直接扫一遍,记录\(A\)后面最长的一段\(P\)即可。
时间复杂度:\(O(n)\)
代码:略

B. Hyperset

题面:https://codeforces.com/contest/1287/problem/B
题解:
可以发现对于任意一对卡,能和它们组成一组的卡片是唯一的。
暴力枚举所有卡对,在map里存储信息,直接查找即可。
时间复杂度:O(\(n^2\)klogn)
代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
    res=0;register D g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
map<string,int>mp;
string s;
char c[2020][110],t[110];
int n,m;
ll ans;
I Match(int x,int y){
    F(i,1,m){
        if(c[x][i]==c[y][i])t[i]=c[x][i];
        else {
            if(c[x][i]=='S'&&c[y][i]=='E')t[i]='T';
            else if(c[x][i]=='S'&&c[y][i]=='T')t[i]='E';
            else if(c[x][i]=='E'&&c[y][i]=='S')t[i]='T';
            else if(c[x][i]=='E'&&c[y][i]=='T')t[i]='S';
            else if(c[x][i]=='T'&&c[y][i]=='S')t[i]='E';
            else t[i]='S';
        }
    }
    s.clear();s.append(t+1);
}
int main(){
    //cin>>t+1;s.append(t+1);
    //F(i,0,s.size()-1)cout<<s[i];
    //return 0;
    read(n);read(m);
    F(i,1,n)cin>>c[i]+1;
    F(i,1,n-1){
        F(j,i+1,n){
            Match(i,j);
            if(!mp.count(s))continue;
            ans+=mp[s];
        }
        s.clear();s.append(c[i]+1);mp.insert(make_pair(s,1));
    }
    cout<<ans;
    return 0;
}

C. Garland

题面:https://codeforces.com/contest/1287/problem/C
题解:考虑DP。
\(f[i][j][k][0/1]\)表示考虑了前\(i\)位,已经在0的地方放了\(j\)个偶数
\(k\)个奇数的最小代价。转移方程分当前位是不是0讨论即可。
时间复杂度:O(\(n^3\))
这已经足够通过本题(我太菜了),考虑如何优化。
发现\(i\)确定时,\(j+k\)是个定值。所以可以把\(j,k\)挤进一个变量里。
时间复杂度:O(\(n^2\))
代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
I read(int &res){
    res=0;re g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
int n,m,a[110],v[110],s[110],f[110][110][2],A,B;
int main(){
    read(n);
    F(i,1,n){
        read(a[i]);s[i]=s[i-1];
        if(!a[i])a[i]=-1,s[i]++;
        else v[a[i]]=1,a[i]&=1;
    }
    F(i,1,n){
        if(!v[i]){
            if(i&1)B++;else A++;
        }
    }
//  F(i,1,n)cout<<a[i]<<" ";
    //cout<<endl;
    C(f,63);
    f[0][0][0]=0;f[0][0][1]=0;
    if(a[1]!=-1){
        F(j,0,min(s[1],A))if(s[1]-j<=B)f[1][j][a[1]]=min(f[0][j][0],f[0][j][1]);
    }
    else{
        F(j,0,min(s[1],A)){
            if(s[1]-j>B)continue;
            if(j)f[1][j][0]=min(f[0][j-1][0],f[0][j-1][1]);
            f[1][j][1]=min(f[0][j][0],f[0][j][1]);
        }
    }
    F(i,2,n){
        if(a[i]!=-1){
            F(j,0,min(s[i],A))if(s[i]-j<=B)f[i][j][a[i]]=min(f[i-1][j][0]+a[i],f[i-1][j][1]+(a[i]^1));
            continue;
        }
        F(j,0,min(s[i],A)){
            if(s[i]-j>B)continue;
            if(j)f[i][j][0]=min(f[i-1][j-1][0],f[i-1][j-1][1]+1);
            f[i][j][1]=min(f[i-1][j][0]+1,f[i-1][j][1]);
        }
    }
    //F(i,1,n)F(j,0,min(s[i],A))cout<<i<<" "<<j<<" "<<f[i][j][0]<<" "<<f[i][j][1]<<endl;
    cout<<min(f[n][A][0],f[n][A][1]);
    return 0;
}

D. Numbers on Tree

题面:https://codeforces.com/contest/1287/problem/D
题解:考虑从下到上解决问题。
每次操作,我们可以把当前节点子树中的点的值都加进一个堆里,
找到分界位置把当前节点的\(a[i]\)赋值,并给其后面的对应点的值+1。
但这样做是不对的,因为有可能在一次操作中,这样的加操作可能会改变
之前子树内点的大小关系。考虑如何避免这个问题。
可以证明,如果有解,一定存在一种方案,使得所有点的\(a[i]\)都不一样。
因此,我们可以记录一下上次堆里的最大值,下次先给所有点的值加上这个最大值,再进堆。
时间复杂度:O(\(n^2\)logn)
代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
I read(int &res){
    res=0;re g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
typedef pair<int,int>pii;
priority_queue<pii>q;
vector<int>e[2020];
int n,m,root,tot,bas,dep[2020],fa[2020],c[2020],w[2020];
pii b[2020];
I D_1(int x,int d){
    dep[x]=d;q.emplace(make_pair(d,x));
    for(auto p:e[x])D_1(p,d+1);
}
I D_2(int x){
    w[x]+=bas;
    b[++tot]=make_pair(w[x],x);
    for(auto p:e[x])D_2(p);
}
int main(){
    read(n);
    F(i,1,n)read(fa[i]),read(c[i]);
    F(i,1,n)if(!fa[i])root=i;else e[fa[i]].emplace_back(i);
    D_1(root,1);
    while(!q.empty()){
        m=q.top().second;q.pop();tot=bas=0;
        for(auto p:e[m]){
            D_2(p);sort(b+1,b+1+tot);bas=b[tot].first;
        }
        if(tot<c[m]){cout<<"NO";return 0;}
        sort(b+1,b+1+tot);w[m]=b[c[m]].first+1;
        F(i,c[m]+1,tot)w[b[i].second]++;
    }
    cout<<"YES"<<endl;
    F(i,1,n)cout<<w[i]<<" ";
    return 0;
}

E Madhouse

题面:https://codeforces.com/contest/1287/problem/D
题解:首先考虑简单版。
我们可以询问\([1,n]\)以及\([1,n-1]\)
发现第一次询问比第二次多了\(n\)个串,这\(n\)个串恰好是
这个串的\(n\)个后缀的乱序版本。找到这\(n\)个串即可还原整个串。
查询次数:O(\(n^2\))

猜你喜欢

转载自www.cnblogs.com/Purple-wzy/p/12160709.html
今日推荐