csp模拟赛 6 9.28
0+40+10+0
一言以蔽之 曰 “一上午白干”
T1 一般图最小匹配
首先,对答案有贡献的点对一定在排序后的位于相邻位置
所以排序后取出所有 \(a_{i+1}-a_{i}\)
但不能像Kruskal一样每次取最小,因为其只需要考虑连通性,不涉及其它限制。
所以用dp或者可反悔贪心取最优解
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int a[50005];
int dp[5005][5005];
signed main()
{
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<=n;i++) dp[i][0]=0;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=min(i/2+1,m);j++)
{
dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+a[i]-a[i-1]);
}
}
cout<<dp[n][m];
}
T2 重定向
从前向后扫描
对于分别考虑 \(a_{i}\) 和 \(a_{i+1}\) 是否选到 0,共四种情况。
用set维护出每个为 0 的位置可以填下的数
另外, 对于 一种情况 \(a_{i}=0\) 并且存在\(j>i\)并且\(a_{j}\)小于其可选的最小至,此时直接删除\(j\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
unordered_map<int,int> ma;
int a[500005];
bool f[500005];
set<int >stk,sty;
int n;
int main()
{
freopen("repeat.in","r",stdin);
freopen("repeat.out","w",stdout);
int T;
cin>>T;
while(T--)
{
cin>>n;
memset(f,0,sizeof(f));
stk.clear();
sty.clear();
ma.clear();
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]) f[a[i]]=1,ma[a[i]]=i;
}
for(int i=1;i<=n;i++)
{
if(!f[i]) stk.insert(i);
else sty.insert(i);
}
int wei=0;
for(int i=1;i<=n;i++)
{
if(a[i]) sty.erase(a[i]);
if(a[i]&&a[i+1])
{
if(a[i]>a[i+1])
{
stk.insert(a[i]);
wei=i;
break;
}
}
if(a[i+1]==0&&a[i])
{
int x=*stk.begin();
if(x<a[i])
{
stk.insert(a[i]);
wei=i;
break;
}
}
if(a[i]==0)
{
int x=*stk.begin();
int y=*sty.begin();
if(y<x)
{
a[i]=y;
sty.erase(y);
wei=ma[y];
//cout<<"__";
break;
}
else
{
a[i]=x;
stk.erase(x);
}
}
}
if(wei==0) wei=n;
for(int i=1;i<=n;i++)
{
if(wei==i) continue;
if(a[i]==0)
{
int x=*stk.begin();
//int y=*sty.begin();
a[i]=x;
stk.erase(x);
}
}
for(int i=1;i<=n;i++)
{
if(wei==i) continue;
//tot++;
cout<<a[i]<<' ';
}
cout<<'\n';
}
}
T3 斯坦纳树
对于当前点集,当且仅当其在原树上形成的虚树存在虚点时答案为 0;
将用边权为0的边相连的点 ,合并为一个大点,只要大点内有一个点存在,即表示该大点存在;
-
可正徐维护,依次加点,将已有点集按\(dfs\) 序排序 ,将新增节点填入,若其与左右两个节点分别形成的lca都位于已有点集内,则无新增虚点
-
也可倒叙删点,对要删除点,若当前相连的边数大于3,则设为虚点;若等于2,则删除,并将与其相连的两个点连边,保持连通性;若等于1 直接删除; 对于每次删除要递归处理
点击查看代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int f,to,next,w;
}ee[600005],e[600005];
int head[300005],cnt1,cnt;
bool del[300005],xvd[300005];
int fa[300005],siz[300005],in[300005],p[300005];
bool ans[300005];
int n,xv;
void add(int f,int t,int w)
{
e[++cnt].to=t;
e[cnt].f=f;
e[cnt].w=w;
e[cnt].next=head[f];
head[f]=cnt;
}
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void merge(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx==fy) return;
fa[fx]=fy;
siz[fy]+=siz[fx];
}
void delet(int x)
{
del[x]=1;
if(in[x]==2)
{
int num1=0,num2=0;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(!del[y]&&num1==0) num1=y;
else if(!del[y]&&num1) num2=y;
}
add(num1,num2,1);
add(num2,num1,1);
in[num1]++;
in[num2]++;
}
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(!del[y])
{
in[y]--;
if(xvd[y]&&in[y]==2)
{
xvd[y]=0;
del[y]=1;
xv--;
delet(y);
}
}
}
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
{
fa[i]=i;
siz[i]=1;
}
for(int i=1;i<n;i++)
{
int x,y,w;
cin>>x>>y>>w;
if(w==0) merge(x,y);
else
{
ee[++cnt1].f=x;
ee[cnt1].to=y;
ee[cnt1].w=w;
}
}
for(int i=1;i<=cnt1;i++)
{
int lx=find(ee[i].f),ly=find(ee[i].to);
in[lx]++,in[ly]++;
add(lx,ly,e[i].w);
add(ly,lx,e[i].w);
}
for(int i=1;i<=n;i++) cin>>p[i];
for(int i=n;i>=1;i--)
{
ans[i]=(xv==0);
int lx=find(p[i]);
siz[lx]--;
if(siz[lx]) continue;
if(in[lx]>=3) xvd[lx]=1,xv++;
else
{
del[lx]=1;
delet(lx);
}
}
for(int i=1;i<=n;i++) cout<<ans[i];
}
T4
不会
网络流
感觉 P2754在暗示什么 打了四遍都在保存前,电脑死机了