2021.7.14
2021.7.14
2021.7.14 模拟赛
Ⅲ
Ⅲ
Ⅲ
目录:
T1.树的直径
T2.积木
T3.软件公司
T4.我图呢
T 1 : T1: T1:树的直径
分析:
看到树上距离 直接考虑
l
c
a
lca
lca
我们可以看出一条性质
:
:
:新直径的一端一定是旧直径的一端
那根据这一点 可以先随便从
2
,
3
,
4
2,3,4
2,3,4中选两点做起始直径 然后枚举一个点
x
x
x
看是起点到
x
x
x距离长 还是终点到
x
x
x距离长 就更新直径的起点或终点
最后直径取
m
a
x
max
max即可 离线搞一搞就可以
O
(
m
l
o
g
n
)
O(mlogn)
O(mlogn)了
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+5;
int m,num,dep[N<<2],fa[N<<2][21],son[N<<2],ans[N<<2];
int dis,dis2,dis3;
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--)
if(fa[x][i]^fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int Dis(int x,int y)
{
int qwq=LCA(x,y);
int res=dep[x]+dep[y]-(dep[qwq]<<1);
return res;
}
void add(int x)
{
dep[++num]=dep[x]+1;
fa[num][0]=x;
for(int i=1;i<=20;i++)
fa[num][i]=fa[fa[num][i-1]][i-1];
}
int main(){
scanf("%d",&m);
fa[2][0]=fa[3][0]=fa[4][0]=1;
dep[1]=0; num=4;
dep[2]=dep[3]=dep[4]=1;
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
son[i]=num+1;
add(x); add(x);
}
int s=2,t=4;
dis=Dis(s,t);
for(int i=1;i<=m;i++)
{
dis2=Dis(s,son[i]);
dis3=Dis(t,son[i]);
if(dis3>=dis&&dis3>=dis2)
{
s=son[i]; ans[i]=dis3;
dis=dis3;
}
else if(dis2>=dis&&dis2>=dis3)
{
t=son[i]; ans[i]=dis2;
dis=dis2;
}
else ans[i]=dis;
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
T 2 : T2: T2:积木
分析:
可以发现 第
x
x
x块积木高度 肯定是第
x
−
1
x-1
x−1块积木高度
+
1
,
−
1
+1,-1
+1,−1或不变
f
i
,
j
f_{i,j}
fi,j为第
i
i
i块积木高度为
j
j
j的方案数 方程很简单:
f
i
,
j
=
f
i
−
1
,
j
−
1
+
f
i
−
1
,
j
+
f
i
−
1
,
j
+
1
f_{i,j}=f_{i-1,j-1}+f_{i-1,j}+f_{i-1,j+1}
fi,j=fi−1,j−1+fi−1,j+fi−1,j+1
会
M
L
E
MLE
MLE 就开滚动数组了
i
i
i表示状态
0
/
1
0/1
0/1
这样还会
T
T
T 因为是水解 开
O
2
O2
O2或
r
e
g
i
s
t
e
r
register
register就可以了
正解数论
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
const int N=2e4+5,Mod=1000000007;
ll n,a[N],h,x,f[2][N<<1];
int main(){
// freopen("brick.in","r",stdin);
// freopen("brick.out","w",stdout);
scanf("%lld",&n);
for(reg int i=1;i<=n;i++)
scanf("%lld",&a[i]);
h=-1;
for(reg int i=1;i<=n;i++)
{
if(i<=(n>>1)+1) h++;
else h--;
memset(f[x],0,sizeof f[x]);
if(i==1)
{
if(a[i]<=0) f[x][0]=1;
else break;
}
else if(a[i]==-1)
for(reg int j=h;j>=0;j--)
f[x][j]=(f[x^1][j+1]+f[x^1][j]+f[x^1][j-1])%Mod;
else
f[x][a[i]]=(f[x^1][a[i]+1]+f[x^1][a[i]]+f[x^1][a[i]-1])%Mod;
x^=1;
}
printf("%lld",f[x^1][0]);
return 0;
}
T 3 : T3: T3:软件公司
分析:
60 % 60\% 60%直接 O ( n m 4 ) O(nm^4) O(nm4) d p dp dp就行了
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=m;k++)
for(int s=0;s<=j;s++)
for(int t=0;t<=k;t++)
f[i][j][k]=min(f[i][j][k],max(f[i-1][j-s][k-t],s*a[i]+t*b[i]));
100
%
100\%
100%
d
p
:
dp:
dp:
f
i
,
j
f_{i,j}
fi,j表示前
i
i
i个人
1
1
1项目做了
j
j
j个
2
2
2项目最多能做的个数
f
i
,
j
=
m
a
x
{
f
i
,
j
,
f
i
−
1
,
j
−
k
+
(
a
n
s
−
k
×
A
i
)
/
B
i
}
∑
k
=
0
j
f_{i,j}=max\{f_{i,j},f_{i-1,j-k}+(ans-k\times A_i)/B_i\}\sum_{k=0}^j
fi,j=max{fi,j,fi−1,j−k+(ans−k×Ai)/Bi}k=0∑j
二分答案就好了
CODE:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=205;
int n,m,f[N][N];
struct qaq{
int a,b;
}qwq[N];
int main(){
// freopen("company.in","r",stdin);
// freopen("company.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d",&qwq[i].a,&qwq[i].b);
int l=0,r=100;
while(l<r)
{
int mid=(l+r)>>1;
memset(f,-127,sizeof f);
f[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=j;k++)
{
if(mid-k*qwq[i].a<0) break;
f[i][j]=max(f[i][j],f[i-1][j-k]+(mid-k*qwq[i].a)/qwq[i].b);
}
if(f[n][m]>=m) r=mid;
else l=mid+1;
}
printf("%d",r);
return 0;
}
T 4 : T4: T4:我图呢
分析:
二分图最大独立集了 把权值都加上
i
n
f
inf
inf
然后黑白染色 构造二分图
对于
Q
1
Q1
Q1 就是求总权值和减去最小割
T
T
T的最大点权和 就是不割的边的边权和 也就是总的权值减去最小割
网络流跑一跑就好了
p s : ps: ps:一开始写了另一种写法 答案和本地跑是一样的 评测出来就是 w a wa wa 不知道为啥 q a q qaq qaq 换写法写调了一天了
CODE (本地过 评测 W A WA WA):
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int N=305;
const ll inf=1e9,INF=1e18;
int n,m,S,T,dep[N],x[N],y[N],qaq[N],vis[N],ovo[N];
int ToT=1,tot,Head[N],head[N];
ll w[N],ans,Ans;
struct node{
int to,next;
ll val;
}edge[N*N<<1],a[N*N<<1];
void addEdge(int x,int y){
edge[++tot]=(node){y,Head[x]};
Head[x]=tot;
}
void add(int x,int y,ll k)
{
a[++ToT]=(node){y,head[x],k};
head[x]=ToT;
a[++ToT]=(node){x,head[y],0};
head[y]=ToT;
}
void work(int x,int st)
{
ovo[x]=st;
if(st==0) add(S,x,w[x]);
else add(x,T,w[x]);
for(int i=Head[x];i;i=edge[i].next)
{
int qwq=edge[i].to;
if(ovo[qwq]==-1) work(qwq,st^1);
}
}
bool bfs()
{
memset(dep,0,sizeof dep);
queue<int> q;
q.push(S);
dep[S]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=a[i].next)
{
int qwq=a[i].to;
if(dep[qwq]==0&&a[i].val>0)
{
dep[qwq]=dep[x]+1;
q.push(qwq);
}
}
}
return dep[T]!=0;
}
ll Dinic(int x,ll k)
{
if(x==T) return k;
ll link=0;
for(int i=qaq[x];i;i=a[i].next)
{
int qwq=a[i].to;
if(dep[qwq]==dep[x]+1&&a[i].val)
{
ll res=Dinic(qwq,min(a[i].val,k));
k-=res;
link+=res;
a[i].val-=res;
a[i^1].val+=res;
if(!k) break;
}
}
if(!link) dep[x]=0;
return link;
}
void getS(int x)
{
vis[x]=1;
for(int i=head[x];i;i=a[i].next)
{
int qwq=a[i].to;
if(a[i].val&&!vis[qwq])
getS(qwq);
}
}
int main()
{
// freopen("graph.in","r",stdin);
// freopen("graph.out","w",stdout);
scanf("%d%d",&n,&m);
ans=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&w[i]);
w[i]+=inf;
ans+=w[i];
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
addEdge(x[i],y[i]);
addEdge(y[i],x[i]);
}
memset(ovo,-1,sizeof(ovo));
S=n+1;T=n+2;
for(int i=1;i<=n;i++)
if(ovo[i]==-1) work(i,0);
for(int i=1;i<=m;i++)
{
if(ovo[x[i]]==1) swap(x[i],y[i]);
add(x[i],y[i],INF);
}
while(bfs())
{
for(int i=1;i<=T;i++)
qaq[i]=head[i];
ans-=Dinic(S,INF);
}
memset(vis,0,sizeof vis);
Ans=0;
getS(S);
for(int i=1;i<=n;i++)
if(ovo[i]^vis[i])
Ans++;
printf("%lld %lld\n",Ans,ans%inf);
for(int i=1;i<=n;i++)
printf("%d",(ovo[i]^vis[i]));
return 0;
}
A C AC AC CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const ll inf=1e9,INF=1e18;
const int N=305,M=2e5+5;
ll n,m,w[N],head[N],qaq[N],frt[M],flow[M],to[M],next[M],val[M];
ll ovo[N][N],ans,tot=1,S,T,col[N];
void color(ll x,ll k)
{
col[x]=k;
for(ll i=1;i<=ovo[x][0];i++)
{
ll qwq=ovo[x][i];
if(!col[qwq]) color(qwq,3-k);
}
}
void add(ll x,ll y,ll k)
{
frt[++tot]=x;
to[tot]=y;
val[tot]=k;
next[tot]=head[x];
flow[tot]=0;
head[x]=tot;
}
queue<ll> q,clear;
ll dep[N],vis[N];
ll bfs()
{
memset(vis,0,sizeof(vis));
vis[S]=1;
memset(dep,0,sizeof(dep));
q=clear;
q.push(S);
while(!q.empty())
{
ll x=q.front();
q.pop();
for(ll i=head[x];i;i=next[i])
{
ll qwq=to[i];
if(val[i]>flow[i]&&(!vis[qwq]))
{
vis[qwq]=1;
dep[qwq]=dep[x]+1;
q.push(qwq);
}
}
}
return dep[T];
}
ll dinic(ll x,ll maxflow)
{
if(maxflow==0||x==T) return maxflow;
ll link=0;
for(ll i=qaq[x];i;i=next[i])
{
ll qwq=to[i];
if(dep[x]+1==dep[qwq])
{
ll res=dinic(qwq,min(maxflow,val[i]-flow[i]));
if(res)
{
link+=res;
maxflow-=res;
flow[i]+=res;
flow[i^1]-=res;
if(!maxflow) break;
}
}
}
return link;
}
ll work(ll sum)
{
ll ans=sum;
while(bfs())
{
for(ll i=1;i<=T;i++)
qaq[i]=head[i];
ans-=dinic(S,INF);
}
return ans;
}
ll ins[N],kel[N];
void getS()
{
q=clear;
q.push(S);
ins[S]=1;
while(!q.empty())
{
ll x=q.front();
q.pop();
for(ll i=head[x];i;i=next[i])
{
ll qwq=to[i];
if(val[i]>flow[i]&&(!ins[qwq]))
{
ins[qwq]=1;
q.push(qwq);
}
}
}
}
int main(){
// freopen("graph.in","r",stdin);
// freopen("graph.out","w",stdout);
ll sum=0;
scanf("%lld%lld",&n,&m);
S=n+1;T=n+2;
for(ll i=1;i<=n;i++)
{
scanf("%lld",&w[i]);
w[i]+=inf;
sum+=w[i];
}
for(ll i=1;i<=m;i++)
{
ll x,y;
scanf("%lld%lld",&x,&y);
ovo[x][++ovo[x][0]]=y;
ovo[y][++ovo[y][0]]=x;
}
for(ll i=1;i<=n;i++)
if(!col[i]) color(i,1);
for(ll i=1;i<=n;i++)
{
if(col[i]==1)
add(S,i,w[i]),add(i,S,0);
if(col[i]==2)
add(i,T,w[i]),add(T,i,0);
}
for(ll i=1;i<=n;i++)
if(col[i]==1)
{
for(ll j=1;j<=ovo[i][0];j++)
{
ll awa=ovo[i][j];
add(i,awa,INF);
add(awa,i,0);
}
}
ans=work(sum);
getS();
for(ll i=2;i<=tot;i++)
{
if(i&1) continue;
if(ins[frt[i]]!=ins[to[i]])
{
if(frt[i]==S||frt[i]==T) kel[to[i]]=1;
if(to[i]==S||to[i]==T) kel[frt[i]]=1;
}
}
ll Ans=0;
for(ll i=1;i<=n;i++)
Ans+=(kel[i]^1);
printf("%lld %lld\n",Ans,ans%inf);
for(ll i=1;i<=n;i++)
putchar((kel[i]^1)+'0');
return 0;
}