F. Tree with Maximum Cost
题目大意:
给你一棵点权树,定义一种计算树的总权值方法,求以谁为根时树的权值最大。
思路:
基础的换根
d
p
dp
dp考虑每次走向子节点的权值变化。
从
r
o
o
t
1
root1
root1走向
r
o
o
t
2
root2
root2绿圈内的点权都要减去,黄圈内的点权都要加上。
写两个
d
f
s
dfs
dfs第一个记录子节的信息,第二个跑
d
p
dp
dp就行了。(注意在换根时信息的更新)
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
ll val[N],n,ans=0,res=0;
vector<int> ve[N];
ll sum[N];
void dfs1(int now,int last,int dep){
res+=val[now]*(ll)dep,sum[now]=val[now];
for(auto it:ve[now]){
if(it==last) continue;
dfs1(it,now,dep+1);
sum[now]+=sum[it];
}
}
void dfs2(int now,int last){
ans=max(ans,res);
for(auto it:ve[now]){
if(it==last) continue;
res-=sum[it]; // 根换到子
sum[now]-=sum[it];
res+=sum[now];
sum[it]+=sum[now];
dfs2(it,now);
sum[it]-=sum[now]; // 换回来
res-=sum[now];
sum[now]+=sum[it];
res+=sum[it];
}
}
int main(){
guo312;
cin>>n;
for(int i=1;i<=n;i++){
cin>>val[i];
}
for(int i=1;i<n;i++){
int u,v; cin>>u>>v;
ve[u].push_back(v);
ve[v].push_back(u);
}
dfs1(1,0,0),dfs2(1,0);
cout<<ans;
return 0;
}
E. Minimal Diameter Forest
题目大意:
给你一个森林,问如何连成一颗直径最小的树。
思路:
树的中心: 所有节点中,到树中其他节点的最远距离 最小的节点。
做法就是把所有树的中心连在直径最长的树的中心(考虑连边后直径的变化和树的中心定义即可证明)
可以发现最终树的直径只有三种情况:
1.原最长直径
2.最长和次长的直径一半+1
3.次长和次次长的直径的一半+2
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
vector<int> ve[N];
int n,m;
int flag[N],d[N],root,len;
void dfs1(int now,int last,int dep){
d[now]=dep,flag[now]=1;
if(d[now]>d[root]) root=now;
for(auto it:ve[now]){
if(it==last) continue;
dfs1(it,now,dep+1);
}
}
void dfs2(int now,int last,int dep){
d[now]=dep;
len=max(len,dep);
for(auto it:ve[now]){
if(it==last) continue;
dfs2(it,now,dep+1);
d[now]=max(d[now],d[it]);
}
if(d[now]==len&&dep==len/2){
root=now;
}
}
struct PW{
int len,u;
}a[N];
bool cmp(PW s1,PW s2){
return s1.len>s2.len;
}
int main(){
guo312;
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v; cin>>u>>v;
ve[u].push_back(v);
ve[v].push_back(u);
}
int cnt=0,ans=0;
for(int i=1;i<=n;i++){
if(flag[i]==0){
root=i,len=0,dfs1(i,0,0),dfs2(root,0,0);
++cnt,a[cnt].len=len/2+(len%2),a[cnt].u=root,ans=max(ans,len);
}
}
sort(a+1,a+1+cnt,cmp);
if(cnt==1){
cout<<len;
return 0;
}
ans=max(a[1].len+a[2].len+1,ans);
if(cnt>=3) ans=max(ans,a[2].len+a[3].len+2);
cout<<ans<<endl;
for(int i=2;i<=cnt;i++){
cout<<a[1].u<<" "<<a[i].u<<endl;
}
return 0;
}
D2. Great Vova Wall (Version 2)
题目大意:
只有一种操作,相邻且高度相同可以放一块砖,问是否可以存在水平情况。
思路:
把相邻且相同的看成一个连通块,最后所有连通块的长度一定是偶数(这样高度才可以相同)
奇数长度的连通块必须由高度相同且同为奇数的抵消,且其中间部分必须是偶数连通块,其整个过程更像一个括号匹配。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
int a[N],b[N],num[N];
int main(){
guo312;
int n,maxn=0; cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i],maxn=max(maxn,a[i]);
}
int idx=0;
for(int i=1;i<=n; ){
int cnt=1;
while(i+1<=n&&a[i]==a[i+1]){
i++,cnt++;
}
++idx,b[idx]=a[i],num[idx]=cnt,++i;
}
stack<int> p; int minn=inf;
for(int i=1;i<=idx;i++){
if(num[i]%2==0){
minn=min(minn,b[i]);
}
else{
if(!p.empty()){
int s=p.top();
if(s==b[i]&&minn<b[i]){
p.pop();
minn=b[i];
}
else{
p.push(b[i]);
minn=inf;
}
}
else{
p.push(b[i]);
minn=inf;
}
}
}
int flag=1;
while(!p.empty()){
int s=p.top(); p.pop();
if(s!=maxn) flag=0;
}
if(flag) cout<<"YES";
else cout<<"NO";
return 0;
}
D1. Great Vova Wall (Version 1)
题目大意:
在 D 2 D2 D2的基础上多了一个操作,可以在一列放。
思路:
可以发现最终状态下所有列同偶或同奇,新增的操作不能改变一列的奇偶状态,只是在 D 2 D2 D2匹配的基础上少了高度的限制。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
int a[N],b[N],num[N];
int main(){
guo312;
int n,maxn=0; cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i],a[i]%=2,maxn=max(maxn,a[i]);
}
int idx=0;
for(int i=1;i<=n; ){
int cnt=1;
while(i+1<=n&&a[i]==a[i+1]){
i++,cnt++;
}
++idx,b[idx]=a[i],num[idx]=cnt,++i;
}
stack<int> p; int f=0;
for(int i=1;i<=idx;i++){
if(num[i]%2==0){
f=1;
}
else{
if(!p.empty()){
int s=p.top();
if(s==b[i]&&f){
p.pop();
f=1;
}
else{
p.push(b[i]);
f=0;
}
}
else{
p.push(b[i]);
f=0;
}
}
}
if(p.size()==0||p.size()==1) cout<<"YES";
else cout<<"NO";
return 0;
}
C. Prefixes and Suffixes
思路:
没有题目大意,直接模拟即可。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e4;
int ans[N],n,flag[N];
struct PW{
string str;
int id;
}a[N];
bool cmp(PW s1,PW s2){
return s1.str.length()<s2.str.length();
}
void init(){
for(int i=1;i<=n*2-2;i++){
ans[i]=0,flag[i]=0;
}
}
string s1;
bool work(){
init(); int re1=0,re2=0;
for(int i=1;i<=n*2-2;i++){
string str=a[i].str; int len=str.length(); string s2=s1.substr(0,len);
if(flag[len]) continue;
if(s2==str){
ans[a[i].id]=1,flag[len]=1;
re1++;
}
}
for(int i=1;i<=n*2-2;i++){
if(ans[a[i].id]) continue;
string str=a[i].str; int len=str.length(); string s2=s1.substr(n-len,n);
//cout<<len<<" "<<s1<<" "<<s2<<endl;
if(s2==str){
re2++;
}
}
if(re1==n-1&&re2==n-1) return 1;
else return 0;
}
int main(){
guo312;
cin>>n; int nn=n*2-2;
for(int i=1;i<=nn;i++){
cin>>a[i].str;
a[i].id=i;
}
sort(a+1,a+1+nn,cmp);
s1=a[nn].str+a[1].str;
if(work()){
for(int i=1;i<=nn;i++){
if(ans[i]) cout<<"P";
else cout<<"S";
}
return 0;
}
s1=a[nn].str+a[2].str;
if(work()){
for(int i=1;i<=nn;i++){
if(ans[i]) cout<<"P";
else cout<<"S";
}
return 0;
}
s1=a[1].str+a[nn].str;
if(work()){
for(int i=1;i<=nn;i++){
if(ans[i]) cout<<"P";
else cout<<"S";
}
return 0;
}
s1=a[2].str+a[nn].str;
if(work()){
for(int i=1;i<=nn;i++){
if(ans[i]) cout<<"P";
else cout<<"S";
}
return 0;
}
}
B. Teams Forming
思路:
直接排序即可
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
int n,a[N];
int main(){
guo312;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+1+n);
ll ans=0;
for(int i=2;i<=n;i+=2){
ans+=a[i]-a[i-1];
}
cout<<ans;
return 0;
}
A. Uniform String
思路:
直接循环输出即可。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
int main(){
guo312;
int t; cin>>t;
while(t--){
int n,k,now=1; cin>>n>>k;
for(int i=1;i<=n;i++){
cout<<char(now+'a'-1);
now++,now%=(k+1);
if(now==0) now++;
}
cout<<endl;
}
return 0;
}