CF1287 div2题解
Posted purple-wzy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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))
以上是关于CF1287 div2题解的主要内容,如果未能解决你的问题,请参考以下文章