基本题
1006题 Maex
题目大意
给定一棵n个节点的树,给每个节点标上0~n-1的权重,求各子树MEX和的最大值
考察内容
树形dp
分析
MEX:即集合内不包括的最大自然数
状态:
dp[i]:节点i的答案;
sz[i]:节点i的子树大小;
边界:
叶子节点,dp[i]=1;
转移:从根节点开始跑dfs.
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+7;
int sz[N];
long long dp[N];
vector<int>g[N];
void dfs(int u,int fa){
sz[u]=1;
dp[u]=0;//初始化
for(auto v:g[u]){//遍历子树
if(v==fa)continue;//确保不是父节点
dfs(v,u);
sz[u]+=sz[v];
dp[u]=max(dp[u],dp[v]);//找MEX值最大的的子树
}
dp[u]+=sz[u];//加上子树大小即为答案
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++)g[i].clear();
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs(1,0);//从根节点开始遍历
cout<<dp[1]<<endl;//根节点最大
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--)solve();
}
1012题 Loop
题目大意
给定一个数组,操作k次,每次将一个数字往后移动若干个位置,求操作所得数组的最大字典序。
考察内容
贪心,排序
分析
取出k个非最大元素,排序后和剩下的归并,注意每行输出不能留空格
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
vector<int>v;
int a[N];
bool cmp(int a,int b){
return a>b;
}
void solve(){
v.clear();//每次初始化
int n,k,maxn=0;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
maxn=max(a[i],maxn);
}//找到最大元素
int cnt=0,p=n+1;//cnt记录已提出的元素数,不得超过k,p记录最后提出元素的位置
for(int i=1;i<=n;i++){
if(a[i]<maxn){
v.emplace_back(a[i]);
cnt++;
if(cnt>=k){
p=i;
break;
}
}
}
sort(v.begin(),v.end(),cmp);//提出的元素从大到小排序
bool f=1;//控制输出,确定是否是第一个元素
for(int i=1;i<p;i++){
if(a[i]>=maxn){//未被提出的元素即为最大值,直接输出
if(f)f=0,cout<<a[i];
else cout<<' '<<a[i];
}
}
int p1=0,len=v.size();
for(int i=p+1;i<=n;i++){//后半部分,归并
while(p1<len&&v[p1]>a[i]){
if(f)f=0,cout<<v[p1];
else cout<<' '<<v[p1];
p1++;
}
if(f)f=0,cout<<a[i];
else cout<<' '<<a[i];
}
while(p1<len){//输出未被输出的提出元素
if(f)f=0,cout<<v[p1];
else cout<<' '<<v[p1];
p1++;
}
cout<<endl;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--)solve();
}
进阶题
1010题 Planar graph
题目大意
在一个平面图中删去若干条边使其无环,求字典序最小的方案
考察内容
图的最大生成森林
分析
对图求最大生成森林
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
const int M=2e5+7;
int f[N];
bool is[M];
struct node{//边
int st,en;
}edge[M];
int getf(int x){//找父节点
if(f[x]==x)return x;
return f[x]=getf(f[x]);
}
int readint(){//快读
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
void solve(){
memset(is,0,sizeof(is));
int ans=0,num[M];
int n,m,u,v;
n=readint();
m=readint();
for(int i=1;i<=m;i++){
u=readint();
v=readint();
edge[i].st=u;
edge[i].en=v;
}
ans=m;
int cnt=m;
for(int i=1;i<=n;i++)f[i]=i;
int k=1;
int fta,ftb;
for(int i=m;i>=1;i--){//从后往前遍历,拆前面的边
fta=getf(edge[i].st);
ftb=getf(edge[i].en);
if(fta!=ftb){
f[fta]=ftb;
cnt--;
is[i]=1;
}
}
cout<<cnt<<endl;
for(int i=1;i<=m;i++){//从前往后遍历,输出字典序最小结果
if(is[i]==0)cout<<i<<' ';
}
cout<<endl;
}
int main(){
int t;
cin>>t;
while(t--)solve();
}
1009题 Map
题目大意
给定大长方形和与其成比例的小长方形,找到一点在大长方形和小长方形上位置一样,输出该点坐标
考察内容
数学
分析
巴纳赫不动点,压缩映射
#include<bits/stdc++.h>
using namespace std;
int X[4],Y[4],x[4],y[4];
double cross(int a,int b,int c,int d){
return a*d-b*c;
}
void solve(){
for(int i=0;i<4;i++)cin>>X[i]>>Y[i];
for(int i=0;i<4;i++)cin>>x[i]>>y[i];
int UX=X[3]-X[0],UY=Y[3]-Y[0],VX=X[1]-X[0],VY=Y[1]-Y[0],ux=x[3]-x[0],uy=y[3]-y[0],vx=x[1]-x[0],vy=y[1]-y[0];
double p=cross(X[0]-x[0],vx-VX,Y[0]-y[0],vy-VY)/cross(ux-UX,vx-VX,uy-UY,vy-VY),q=cross(ux-UX,X[0]-x[0],uy-UY,Y[0]-y[0])/cross(ux-UX,vx-VX,uy-UY,vy-VY);
printf("%.6lf %.6lf\n",x[0]+p*ux+q*vx,y[0]+p*uy+q*vy);
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--)solve();
}