zr2019暑期高端峰会AB组day2
A. 小K与赞助
好妙的一道费用流建模题,三十多个人A了,我都没想到,真是网络流白学了。
建模方式如下:
- S向两个树根连边,流量为树根处的限制,费用为零
- 对于每个点,它的父亲向它连一条流量为该棵子树限制,费用为零的边
- 对于两棵树上相应的两个点,我们只允许其中一个产生贡献,于是我们再建出它的第三个复制产生的点,原来这两个点都向这第三个点连一条流量随便,费用为零的边
- 每个“第三点”向T连流量为1费用为 a i a_i ai的边,上面之所以随便是因为我们在这里限制
- 那么答案就是最大费用最大流
- 某个点产生贡献的意义就是,水流到这个点并从这个点流出去至T
B. 小K与重建计划
下面关于结论的部分就不写证明了,反正连我都能看出的结论就是很显然的结论
- 对于一棵树,他存在一种方案当且仅当点权和大于等于边权和,我们构造方案的方式就是每次枚举每一条边,看看能不能合并,能合就合,最后总能合成一个点
- 对于图,我们求出最小生成树然后按上面的方法做,于是得到了 O ( n 2 ) O(n^2) O(n2)的i做法,拿到了49分
- 我们考虑在构造方案的时候省省时间,我们在最小生成树上dfs下去,我们定义 s [ u ] s[u] s[u]为u的子树的点权和减去边权和再减去它的父边的边权,如果这个子树能缩成一个点当且仅当它的点权和大于等于它的边权和,这就是一个子问题,于是这些子树先合并起来,对于 s [ u ] ≥ 0 s[u]\geq 0 s[u]≥0的子树将它合并之后必定能将根节点的可供用权值变大,所以我们也先缩这些子树,这时候再做那些其他的原本不能直接合并的边就行了
C. 小K与作品
- 一个数是完全平方数即它的所有质因子的指数是偶数,我们不关心多少,只关心奇偶
- 当n不大的时候,质因子数不会很多, n ≤ 1000 n \leq 1000 n≤1000的时候也就一百来个,于是就有了一个朴素的想法,用一个长度为质因子个数bitset维护某个数的每个质因子上的指数的奇偶性,然后再搞个线性基
- 我们从右往左加入元素,假如目前线性基中插入的是
(
l
,
r
]
(l,r]
(l,r]的所有元素,那么我们拿
l
l
l进去跑,看看能不能跑出零,就知道
f
(
l
)
f(l)
f(l)是不是
r
r
r,于是就有51分,
我真菜,连到这都不会 - 那么当n大了,大于1000的质因子只会又最多有一个,那么bitset里仍然只维护 ≤ 1000 \leq 1000 ≤1000的质因子,大于1000的质因子,跑线性基的时候多传一个参数特判即可
小结论:每次答案最多只有一个数,设 g ( x ) g(x) g(x)为x左边最大的数符合题意,则 f ( g ( x ) ) = x f(g(x))=x f(g(x))=x,那我们每次只要找到一个就能停止了-- 复杂度 O ( n q 2 64 ) O(\frac{nq^2}{64}) O(64nq2),q是小于1000的质因子个数
T1赛场代码
两棵树一样的写错,拿了枚举的分
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(b);i>=(a);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define pb push_back
using namespace std;
typedef long long ll;
const int N=505;
int n,a[N],rt1,rt2,x,y,q1,q2,a1[N],a2[N],p1[N],p2[N],lim1[N],lim2[N],ans=0,pre[N];
int k[N],b[N][N];
int cnt[N],tag[N];
vector <int> G[N],T[N];
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
bool cmp(const int a,const int b)
{
return a>b;
}
void DFS(int u,int fa)
{
int len=G[u].size();
FOR(i,0,len-1)
{
int v=G[u][i];
if (v==fa) continue;
DFS(v,u);
FOR(j,1,k[v]) b[u][++k[u]]=b[v][j];
}
b[u][++k[u]]=a[u];
sort(b[u]+1,b[u]+k[u]+1,cmp);
k[u]=min(k[u],lim1[u]);
k[u]=min(k[u],lim2[u]);
return;
}
void Solve1()
{
DFS(rt1,0);
FOR(i,1,k[rt1]) ans+=b[rt1][i];
printf("%d\n",ans);
return;
}
int check1(int u,int fa)
{
int len=G[u].size();
cnt[u]=0;
FOR(i,0,len-1)
{
int v=G[u][i];
if (v==fa) continue;
int flag=check1(v,u);
cnt[u]+=cnt[v];
if (!flag) return 0;
}
if (tag[u]==1) cnt[u]++;
if (cnt[u]>lim1[u]) return 0;
return 1;
}
int check2(int u,int fa)
{
int len=T[u].size();
cnt[u]=0;
FOR(i,0,len-1)
{
int v=T[u][i];
if (v==fa) continue;
int flag=check2(v,u);
cnt[u]+=cnt[v];
if (!flag) return 0;
}
if (tag[u]==2) cnt[u]++;
if (cnt[u]>lim2[u]) return 0;
return 1;
}
int Check()
{
if (check1(rt1,0)&&check2(rt2,0)) return 1;
else return 0;
}
void brute(int dep,int fen)
{
if (fen+pre[n]-pre[dep-1]<ans) return;
if (dep>n)
{
if (Check()) ans=max(ans,fen);
return;
}
FOR(i,0,2)
{
tag[dep]=i;
brute(dep+1,fen+(tag[dep]?a[dep]:0));
tag[dep]=0;
}
return;
}
void Brute()
{
brute(1,0);
printf("%d\n",ans);
return;
}
int main()
{
mem(lim1,0x3f);
mem(lim2,0x3f);
n=read();
FOR(i,1,n) a[i]=read(),pre[i]=pre[i-1]+a[i];
rt1=read();
FOR(i,1,n-1) x=read(),y=read(),G[x].pb(y),G[y].pb(x);
rt2=read();
FOR(i,1,n-1) x=read(),y=read(),T[x].pb(y),T[y].pb(x);
q1=read();
FOR(i,1,q1) a1[i]=read(),p1[i]=read(),lim1[a1[i]]=min(p1[i],lim1[a1[i]]);
q2=read();
FOR(i,1,q2) a2[i]=read(),p2[i]=read(),lim2[a2[i]]=min(p2[i],lim2[a2[i]]);
if (n<=14) Brute();
else if (rt1==rt2) Solve1();
return 0;
}
/*
12
8 5 6 7 11 12 1 10 13 3 4 2
1
1 2
1 3
2 4
2 5
2 6
3 7
3 8
8 12
4 9
4 10
4 11
1
1 2
1 3
2 4
2 5
2 6
3 7
3 8
8 12
4 9
4 10
4 11
2
2 4
8 1
2
4 2
1 6
*/
T1赛后代码
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define pb push_back
using namespace std;
const int N=6e5+5;
const int inf=1e9+7;
int n,a[N],x,y,q1,q2,a1[N],a2[N],p1[N],p2[N],lim1[N],lim2[N],rt1,rt2;
int tot=1,f[N],nxt[N<<1];
int vis[N],dis[N],minf[N],pre[N],s,t,maxflow=0,maxcost=0;
vector <int> G[N],T[N];
queue <int> q;
struct E
{
int u,v,w,flow;
}e[N<<1];
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
void Add(int u,int v,int w,int flow)
{
tot++;
nxt[tot]=f[u];
f[u]=tot;
e[tot]=(E){u,v,w,flow};
return;
}
void Addedge(int u,int v,int w,int flow)
{
Add(u,v,w,flow);
Add(v,u,-w,0);
}
int SPFA()
{
while (q.size()) q.pop();
mem(dis,0x3f);
mem(vis,0);
mem(minf,0x3f);
mem(pre,0);
dis[s]=0;
vis[s]=1;
q.push(s);
while (q.size())
{
int tmp=q.front();
q.pop();
vis[tmp]=0;
for (register int j=f[tmp];j!=-1;j=nxt[j])
{
int v=e[j].v;
if (!e[j].flow) continue;
if (dis[v]>dis[tmp]+e[j].w)
{
minf[v]=min(minf[tmp],e[j].flow);
pre[v]=j;
dis[v]=dis[tmp]+e[j].w;
if (!vis[v]) q.push(v),vis[v]=1;
}
}
}
if (dis[t]!=0x3F3F3F3F) return 1;
else return 0;
}
void Update()
{
maxflow+=minf[t];
maxcost-=dis[t]*minf[t];
int now=t;
while (now!=s)
{
e[pre[now]].flow-=minf[t];
e[pre[now]^1].flow+=minf[t];
now=e[pre[now]].u;
}
return;
}
void DFS1(int u,int fa)
{
int len=G[u].size();
FOR(i,0,len-1)
{
int v=G[u][i];
if (v==fa) continue;
DFS1(v,u);
}
if (fa) Addedge(fa,u,0,lim1[u]);
else Addedge(s,u,0,lim1[u]);
return;
}
void DFS2(int u,int fa)
{
int len=T[u].size();
FOR(i,0,len-1)
{
int v=T[u][i];
if (v==fa) continue;
DFS2(v,u);
}
if (fa) Addedge(fa+n,u+n,0,lim2[u]);
else Addedge(s,u+n,0,lim2[u]);
return;
}
void Build()
{
s=3*n+1,t=3*n+2;
// Addedge(s,rt1,0,inf);
// Addedge(s,rt2+n,0,inf);
DFS1(rt1,0);
DFS2(rt2,0);
FOR(i,1,n)
{
Addedge(i,i+n+n,0,1);
Addedge(i+n,i+n+n,0,1);
Addedge(i+n+n,t,-a[i],1);
}
return;
}
void line()
{
for (register int j=2;j<=tot;j+=2) printf("%d %d %d %d\n",e[j].u,e[j].v,e[j].w,e[j].flow);
return;
}
int main()
{
mem(f,-1);
n=read();
FOR(i,1,n) lim1[i]=lim2[i]=inf;
FOR(i,1,n) a[i]=read();
rt1=read();
FOR(i,1,n-1) x=read(),y=read(),G[x].pb(y),G[y].pb(x);
rt2=read();
FOR(i,1,n-1) x=read(),y=read(),T[x].pb(y),T[y].pb(x);
q1=read();
FOR(i,1,q1) a1[i]=read(),p1[i]=read(),lim1[a1[i]]=min(lim1[a1[i]],p1[i]);
q2=read();
FOR(i,1,q2) a2[i]=read(),p2[i]=read(),lim2[a2[i]]=min(lim2[a2[i]],p2[i]);
Build();
// line();
while (SPFA()) Update();
printf("%d\n",maxcost);
return 0;
}
T2赛场代码
想到了结论,写了 O ( n 2 ) O(n^2) O(n2)的暴力枚举边
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(b);i>=(a);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define pb push_back
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,a[N],x,y,z,uu[N],vv[N],ww[N];
int tot=0,f[N],nxt[N<<1],tote=0,first[N],nxxt[N<<1];
int used[N];
int fa[N],ans[N],vis[N];
int tag[N<<1];
int line[N],l=1,r=0;
ll val[N],sum_e=0,sum_p=0;
struct E
{
int u,v,w,id;
}e[N<<1],edge[N<<1];
bool cmp(const E a,const E b) {return a.w<b.w;}
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
void Add(int u,int v,int w,int id)
{
tot++;
nxt[tot]=f[u];
f[u]=tot;
e[tot]=(E){u,v,w,id};
return;
}
void Addedge(int u,int v,int w,int id)
{
tote++;
nxxt[tote]=first[u];
first[u]=tote;
edge[tote]=(E){u,v,w,id};
return;
}
int Getfa(int x) {return (x==fa[x])?x:fa[x]=Getfa(fa[x]);}
void Join(int x,int y)
{
int fx=Getfa(x),fy=Getfa(y);
if (fx==fy) return;
fa[fx]=fy;
return;
}
void Kruscal()
{
int cnt=0;
sort(e+1,e+tot+1,cmp);
FOR(i,1,n) fa[i]=i;
FOR(j,1,tot)
{
int u=e[j].u,v=e[j].v;
int fu=Getfa(u),fv=Getfa(v);
if (fu==fv) continue;
Join(fu,fv);
tag[j]=1;
sum_e+=1LL*e[j].w;
cnt++;
if (cnt==n-1) break;
}
return;
}
int ready(int e)
{
int u=edge[e].u,v=edge[e].v;
int fu=Getfa(u),fv=Getfa(v);
if (val[fu]+val[fv]-1LL*ww[edge[e].id]>=0) return 1;
else return 0;
}
void Make_plan()
{
FOR(i,1,n) fa[i]=i,val[i]=a[i];
FOR(i,1,n-1)
FOR(j,1,tote) if (ready(j)&&(!used[edge[j].id]))
{
used[edge[j].id]=1;
int u=edge[j].u,v=edge[j].v;
int fu=Getfa(u),fv=Getfa(v);
val[fv]=val[fu]+val[fv]-edge[j].w;
Join(fu,fv);
ans[i]=edge[j].id;
break;
}
return;
}
void Debug()
{
printf("%d %d\n",n,m);
FOR(i,1,n) printf("%d ",a[i]);
printf("\n");
FOR(i,1,m) printf("%d %d %d\n",uu[i],vv[i],ww[i]);
return;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("myans.out","w",stdout);
mem(f,-1);
mem(first,-1);
n=read(),m=read();
FOR(i,1,n) a[i]=read(),sum_p+=1LL*a[i];
FOR(i,1,m) x=read(),y=read(),z=read(),Add(x,y,z,i),Add(y,x,z,i),uu[i]=x,vv[i]=y,ww[i]=z;
Kruscal();
if (sum_e>sum_p) {printf("0\n");exit(0);}
FOR(i,1,tot) if (tag[i]) Addedge(e[i].u,e[i].v,e[i].w,e[i].id),Addedge(e[i].v,e[i].u,e[i].w,e[i].id);
Make_plan();
// Debug();
printf("1\n");
FOR(i,1,n-1) printf("%d ",ans[i]);
return 0;
}
T2赛后代码
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(b);i>=(a);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define pb push_back
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,a[N],x,y,z,uu[N],vv[N],ww[N];
int tot=0,f[N],nxt[N<<1],tote=0,first[N],nxxt[N<<1];
ll s[N];
int fa[N],ans[N],vis[N];
int tag[N<<1];
ll val[N],sum_e=0,sum_p=0;
struct E
{
int u,v,w,id;
}e[N<<1],edge[N<<1];
bool cmp(const E a,const E b) {return a.w<b.w;}
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
void Add(int u,int v,int w,int id)
{
tot++;
nxt[tot]=f[u];
f[u]=tot;
e[tot]=(E){u,v,w,id};
return;
}
void Addedge(int u,int v,int w,int id)
{
tote++;
nxxt[tote]=first[u];
first[u]=tote;
edge[tote]=(E){u,v,w,id};
return;
}
int Getfa(int x) {return (x==fa[x])?x:fa[x]=Getfa(fa[x]);}
void Join(int x,int y)
{
int fx=Getfa(x),fy=Getfa(y);
if (fx==fy) return;
fa[fx]=fy;
return;
}
void Kruscal()
{
int cnt=0;
sort(e+1,e+tot+1,cmp);
FOR(i,1,n) fa[i]=i;
FOR(j,1,tot)
{
int u=e[j].u,v=e[j].v;
int fu=Getfa(u),fv=Getfa(v);
if (fu==fv) continue;
Join(fu,fv);
tag[j]=1;
sum_e+=1LL*e[j].w;
cnt++;
if (cnt==n-1) break;
}
return;
}
void Get_s(int u,int fa)
{
s[u]=a[u];
for (register int j=first[u];j!=-1;j=nxxt[j])
{
int v=edge[j].v;
if (v==fa) s[u]-=edge[j].w;
else
{
Get_s(v,u);
s[u]+=s[v];
}
}
return;
}
void Shrink(int u,int fa)
{
for (register int j=first[u];j!=-1;j=nxxt[j])
{
int v=edge[j].v;
if (v==fa) continue;
if (s[v]>=0)
{
Shrink(v,u);
ans[++ans[0]]=edge[j].id;
}
}
for (register int j=first[u];j!=-1;j=nxxt[j])
{
int v=edge[j].v;
if (v==fa) continue;
if (s[v]<0)
{
if (s[v]+edge[j].w>=0)
{
Shrink(v,u);
ans[++ans[0]]=edge[j].id;
}
else
{
ans[++ans[0]]=edge[j].id;
Shrink(v,u);
}
}
}
return;
}
void Make_plan()
{
Get_s(1,0);
Shrink(1,0);
return;
}
void Debug()//for spj
{
printf("%d %d\n",n,m);
FOR(i,1,n) printf("%d ",a[i]);
printf("\n");
FOR(i,1,m) printf("%d %d %d\n",uu[i],vv[i],ww[i]);
return;
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("myans.out","w",stdout);
mem(f,-1);
mem(first,-1);
n=read(),m=read();
FOR(i,1,n) a[i]=read(),sum_p+=1LL*a[i];
FOR(i,1,m) x=read(),y=read(),z=read(),Add(x,y,z,i),Add(y,x,z,i),uu[i]=x,vv[i]=y,ww[i]=z;
Kruscal();
if (sum_e>sum_p) {printf("0\n");exit(0);}
FOR(i,1,tot) if (tag[i]) Addedge(e[i].u,e[i].v,e[i].w,e[i].id),Addedge(e[i].v,e[i].u,e[i].w,e[i].id);
Make_plan();
// Debug();
printf("1\n");
FOR(i,1,n-1) printf("%d ",ans[i]);
return 0;
}
T3赛场代码
小数据用手打了个表,100和1000的表好像最后都不太够时间写了,线性基又没想到
#include<bits/stdc++.h>
using namespace std;
int n,ans[21]={0,1,0,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1},a[21]={0,1,0,0,4,0,2,0,3,9,5,0,6,0,7,8,16,0,10,0,12};
int zhi(int m)
{
if (m==1) return 0;
if (m==2) return 1;
for (int i=2;i*i<=m;i++) if (m%i==0) return 0;
return 1;
}
int main()
{
scanf("%d",&n);
if (zhi(n)) {printf("0\n");exit(0);}
if (n<=20) {printf("%d\n",ans[n]);if (ans[n]) printf("%d\n",a[n]);exit(0);}
return 0;
}
T3赛后代码
#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
using namespace std;
const int N=2e6+5;
int n,cnt=0,pri[N],big[N],vis[N],vis_p[N],vis_big[N],lim;
bitset<300> p[N],msk[N];
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
int su(int m)
{
if (m==1) return 0;
if (m==2) return 1;
for (int i=2;i*i<=m;i++) if (m%i==0) return 0;
return 1;
}
void init()
{
FOR(i,2,n)
{
if (!vis[i])
{
pri[++cnt]=i;
if (i<=1000) msk[i][cnt]=1,lim=cnt;
else big[i]=i;
// cout<<msk[i]<<endl;
}
for (int j=1;pri[j]*i<=n&&j<=cnt;j++)
{
vis[i*pri[j]]=1;
big[i*pri[j]]=max(big[i],big[pri[j]]);
msk[i*pri[j]]=msk[i]^msk[pri[j]];
if (i%pri[j]==0) break;
}
}
return;
}
void Insert(bitset<300> x,int big)
{
if ((!vis_big[big])&&(big)) {vis_big[big]=1;p[big]=x;return;}
if (big) x^=p[big];
For(i,lim,1) if (x[i])
{
if (!vis_p[i])
{
p[i]=x;
vis_p[i]=1;
return;
}
x^=p[i];
}
return;
}
int Query(bitset<300> x,int big)
{
if ((!vis_big[big])&&big) return 0;
if (big) x^=p[big];
For(i,lim,1) if (x[i])
{
if (!vis_p[i]) return 0;
x^=p[i];
}
return 1;
}
int main()
{
n=read();
init();
// FOR(i,1,n) cout<<msk[i]<<endl;
if (su(n)) {printf("0\n");exit(0);}
int tmp=sqrt(n);
if (tmp*tmp==n) {printf("1\n%d\n",n);exit(0);}
For(i,n-1,1)
{
Insert(msk[i],big[i]);
// FOR(j,1,cnt) cout<<p[j]<<endl;
if (Query(msk[n],big[n])) {printf("1\n%d\n",i);exit(0);}
}
printf("0\n");
return 0;
}
在后面偷偷地%%%pbpb,cdw,ntf