好久没打CF了,低迷了一段时间后又忙于搬砖和摸鱼等等0_0
工作后发现有时间写写题和题解也是一种享受的,当然水平还是一如既往的菜的...
C、Prefixes and Suffixes
题目大意:有一个长度为n的字符串,给出分别长度为1~n-1的前缀和后缀的乱序排列,总共有(2n-2)个排列,问每个给出的排列是前缀还是后缀。
思路:由最长的两个n-1的排列可以确定4种字符串,因为数据也不大,生成后依次进行检测是否满足要求即可。
代码:
#include
#define _Out for(int i=0;i >S[100];
bool ans[200];
bool check(string str){
for(int i=1;i>tmp;
S[tmp.length()].push_back(make_pair(tmp,i));
}
if(check(S[n-1][0].fi+S[n-1][1].fi[n-2]))_Out;
else if(check(S[n-1][0].fi[0] + S[n-1][1].fi))_Out;
else if(check(S[n-1][1].fi+S[n-1][0].fi[n-2]))_Out;
else if(check(S[n-1][1].fi[0] + S[n-1][0].fi))_Out;
}
D1. Great Vova Wall (Version 1)
题目大意:类似于俄罗斯方块,有任意数量个2*1的方块,可以选择横放或者竖放,现在有一个宽度为n,高度不限的平面。给出每个位置的方块高度,问有没有一种放置方块的方式可以使得放满某一高度下的所有位置。
思路:
因为可以竖放,所以整个空间的高度可以视作模2.
从左往右依次进行维护,尽量使得左边的空间都放满,可以发现最后的情况一定是两种:
根据当前的高度和左边的高度的奇偶关系,结合左边空间的放置情况,可以做出以下操作:
代码:
#include
using namespace std;
int main()
{
int type = 0;
int n,a,b,row=0;
scanf("%d%d",&n,&a);a&=1;
for(int i=1;i=1){
type-=1;
a^=1;
}
}
else{
if(type||!row)++type;
a ^= 1;
}
}printf("%s\n",type?"NO":"YES");
return 0;
}
D2. Great Vova Wall (Version 2)
题目大意:规则同上,只是不能竖放,最后询问能否放满
思路:
若当前方格高度大于左边的方格高度,必定无法放满。
若当前方格高度等于左边的方格高度,那么可以变为任意大于当前的高度。
那么维护一个递减栈,当出现等于的情况,就向栈底进行合并即可。
代码:
#include
#define fi first
#define se second
using namespace std;
stack > S;
void oper(){
auto t = S.top();S.pop();
while(!S.empty()){
S.top().se+=t.se;
t = S.top();S.pop();
if(t.se&1)break;
}S.push(t);
}
int main()
{
int n,x;
scanf("%d%d",&n,&x);
S.push(make_pair(x,1));
for(int i=1;ix){
S.push(make_pair(x,1));
}else if(S.top().fi==x){
S.top().se+=1;
oper();
}else {
if((S.top().se%2)==0){
S.top()=make_pair(x,S.top().se+1);
oper();
}else {
S.push(make_pair(x,1));
break;
}
}
}printf("%s\n",S.size()>1?"NO":"YES");
}
E. Minimal Diameter Forest
题目大意:给出一片森林,自由的进行连点使其变成一棵树,询问能得到的最短的树上最长距离。
思路:先找森林里每棵树上到最远节点距离最短的点(忘记怎么叫了),然后按最远距离进行排序,这时一个点就代表了一棵树,把最大的树和其余的相连,处理好连接到最大的树的点的最长距离以及次长距离就可以了
代码:
#include
#include
#include
#include"bits/stdc++.h"
#define pii pair
#define fi first
#define se second
using namespace std;
int n,m,ans;
int root[1005],dis[1005];
vectorE[1005];
map< int,pii >mi;
inline int _find(int x){return x!=root[x]?root[x]=_find(root[x]):x;}
priority_queue< pii > Q;
bool vis[1005];
vector< pii > V;
void GetLongDis(int x){
int len = -1 , y = x , fy = _find(x);
queueS;
S.push(x);
memset(vis,0,sizeof(vis));
vis[x] = true;
while(!S.empty()){
int sz = S.size();
++len;
while(sz--){
x = S.front();S.pop();
for(int i=0;ise = min(iter->se,make_pair(len,y));
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)root[i]=i;
for(int a,b,i=0;imax1)swap(max1,max2);
Q.pop();
}ans = max(ans,max1+max2);
printf("%d\n",ans);
for(auto iter: V)
printf("%d %d\n",iter.fi,iter.se);
return 0;
}
F. Tree with Maximum Cost
题目大意:给定一棵树,以及树上每个节点的值。求一个最大的树的代价:选定一个点,对应的代价为到其余点的边数量乘以那个点的值 之和。
思路:
比较基础的树形DP,先得到根的代价后,转移的时候考虑一下对应的边的带来的贡献。
代码:
#include
#define N 200005
#define LL long long
using namespace std;
int n;
vectorE[N];
LL sum,son[N],ans[N],val[N],ANS;
void dfs_1(int v=1,int fa=0,int dis=0){
ans[1] += val[v] * dis ;
for(int i=0;i