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\))

原文地址:https://www.cnblogs.com/Purple-wzy/p/12160709.html

时间: 2024-12-17 02:54:21

CF1287 div2题解的相关文章

CF1169(div2)题解报告

CF1169(div2)题解报告 A 不管 B 首先可以证明,如果存在解 其中必定有一个数的出现次数大于等于\(\frac{m}{2}\) 暴力枚举所有出现次数大于等于$\frac{m}{2} $的数 剩下的数看看有没有一个公共数即可 由于出现次数大于等于$\frac{m}{2} $的数不会太多 所以时间复杂度应该是\(O(n)\)的 #include<cstdio> #include<iostream> #include<queue> #include<algo

[Topcoder]SRM632 div2 题解

TC第一次解出三题--当了次room leader-- 感觉这次的题比较弱,代码量也很小,都是在拼手速了 250 RunningAroundPark 题意很好懂,一圈跑道上有N棵树,现给你遇到这些树的顺序,问最少需要多少走圈才能遇到相应的序列 直接判断a[i]<=a[i+1]即可 首先假定走了一圈 #include <cstdlib> #include <cctype> #include <cstring> #include <cstdio> #inc

codeforces #275 div2题解

A题目大意: 给你l,r,问你在l~r之间,是否存在 a和b互质 , b和c互质 ,但是 a,c不互质 的情况:其中l<=a<b<c<=r;如果存在,就输出a,b,c;不存在就输出-1: 其中(1 ≤ l ≤ r ≤ 1018; r - l ≤ 50). - -r-l<=50,这么水我也是醉了,开个longlong , 枚举他们是否满足以上要求即可,顺便复习了一下辗转相除: #include <cstdio> #include <cstring> #i

Codeforces Round #467(Div2)题解

凌晨起来打CF,0:05,也是我第一次codeforces 第一题: 我刚开始怀疑自己读错题了,怎么会辣么水. 判除了0的数字种类 #include <cstdio> int n,ans=0; bool hsh[610]; int main(){ scanf("%d",&n);int i; for(i=1;i<=n;++i){ int x;scanf("%d",&x);if(!hsh[x] && x)++ans,hs

codeforce 285 div2 D 题解

codeforce 285 div2 D 题解 说明 这道题目是看了思路分析才知道的,关键问题在于数据量过大,需要快速检索的同时不能辅助空间过大. 因此利用了下面3种方法结合解决该问题 康拓展开与逆康拓展开 树状数组 二分查找 代码 /** * @brief Codeforces Round #285 (Div. 2) d * @file d.cpp * @author mianma * @created 2015/01/27 18:18 * @edited 2015/01/29 22:45 *

codechef MAY18 div2 部分题解

T1 https://www.codechef.com/MAY18B/problems/RD19 刚开始zz了,其实很简单. 删除一个数不会使gcd变小,于是就只有0/1两种情况 T2 https://www.codechef.com/MAY18B/problems/XORAGN 我们可以把B序列看做一个矩阵 那么$A(i,j)$和$A(j,i)$会抵消掉 因此答案就是$\sum_1^n A(i,i) + A(i,i)$ T3 https://www.codechef.com/MAY18B/pr

2019 GUDT WPTC 1 Div2 Problem E(题解) codeforces 115B

原题 题目大意 题目背景是割草,给一个图,然后给出图中草的坐标的,然后要把这些草全部割掉,工作员从图中的(1,1)坐标出发,刚开始面向右边,每次只能进行两个操作 (1)往面向的方向走一格(2)往下走一格并且转向.问工作员把草全部割掉至少走几步? 题目分析 有题可知工作员的行进方向,第一行朝右,第二行朝左,第三行又朝右.因此只要想明白题目还是很好解的,具体过程我会在代码里注释. 代码 1 #include <cstdio> 2 #include <cmath> 3 #include

codeforces #593 div2 ABCD 题解

A. Stones Description 给出3堆物品,个数分别为a,b,c 有两种取数方式,a1b2,b1c2,问最多取多少物品 Solution $O(n^2)暴力$ 1 #include <algorithm> 2 #include <cctype> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <cstring> 7 #inclu

Codeforces 583 DIV2 Robot&#39;s Task 贪心

原题链接:http://codeforces.com/problemset/problem/583/B 题意: 就..要打开一个电脑,必须至少先打开其他若干电脑,每次转向有个花费,让你设计一个序列,使得总花费最小. 题解: 就傻傻的走就好..从左走到右,再走回来,更新序列和答案就好. 代码: #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #define MA