省选模拟32
A. 梦批糼
考虑容斥求,至少选中一次每个点的概率
于是只需要求出有多少个合法的长方体不经过这个点
然后再用总的概率减去每次都选择了不经过的概率再乘上权值
于是枚举长方体的左下角,再枚举长方体的长和高,发现此时宽是单调的
然后再差分一下就能求出经过每个点的长方体个数
我用的暴力跑过去的
B. 等你哈苏德
发现做差的绝对值小于等于 \(1\)
然后考虑每个区间被覆盖的情况,要么是奇数次,要么是偶数次
偶数次的话答案只能为 \(0\)
将黑白色分别看成 \(+1\) 和 \(-1\)
将修改差分一下,于是区间的差分数组也必须为 \(0\)
转化一下,将连接的左右端点建边
再考虑将染色定一下向,黑色为 \(l\) 向 \(r+1\) 连,白色为 \(r+1\) 向 \(l\) 连,没有染色就是一条无向边
于是若区间差分数组为 \(0\) ,也就相当与存在一条欧拉回路
如果都没有被染色,那么就是无向图欧拉回路的判定
有被染色的就考虑混合图欧拉回路的判定,可以写一个网络流
再看被覆盖奇数次的区间,可以额外加一条 \(l,r\) 的无向边
这样就能将 \(+1\) 和 \(-1\) 调整成 \(0\) 了
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,S,T,sum;
int O[60010],tot;
int in[60010],out[60010],num[60010];
int id[30010];
struct data{int l,r,k;}L[30010];
int dis[60010],q[60010],h,t;
int head[60010],HD[60010],ver[600010],to[600010],edge[600010];
inline void add(int x,int y,int z){
ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;
ver[++tot]=x;edge[tot]=0;to[tot]=head[y];head[y]=tot;
}
inline bool bfs(){
for(int i=1;i<=T;i++) dis[i]=inf;dis[S]=0;q[h=t=1]=S;memcpy(head,HD,sizeof(head));
while(h<=t){
int x=q[h++];
for(int i=head[x];i;i=to[i]) if(edge[i]){
int y=ver[i];
if(dis[y]>dis[x]+1){
dis[y]=dis[x]+1;
q[++t]=y;
}
}
if(x==T) return true;
}
return false;
}
int dfs(int x,int in){
if(x==T) return in;
int res=in,go;
for(int i=head[x];i;head[x]=i=to[i]) if(edge[i]){
int y=ver[i];
if(dis[y]!=dis[x]+1) continue;
go=dfs(y,min(edge[i],res));
if(go) res-=go,edge[i]-=go,edge[i^1]+=go;
else dis[y]=inf;
if(!res) break;
}
return in-res;
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("wait.in","r",stdin);
freopen("wait.out","w",stdout);
m=read(),n=read();
for(int i=1;i<=m;i++){
O[++tot]=L[i].l=read();
O[++tot]=L[i].r=read()+1;
L[i].k=read();
}
sort(O+1,O+1+tot);n=unique(O+1,O+1+tot)-O-1;S=n+1,T=n+2;tot=1;
for(int i=1;i<=m;i++){
L[i].l=lower_bound(O+1,O+1+n,L[i].l)-O;
L[i].r=lower_bound(O+1,O+1+n,L[i].r)-O;
}
for(int i=1;i<=m;i++){
num[L[i].l]++,num[L[i].r]--;
if(L[i].k==-1){out[L[i].l]++;in[L[i].r]++;add(L[i].r,L[i].l,1);id[i]=tot;}
else if(L[i].k==0){out[L[i].l]++;in[L[i].r]++;}
else{in[L[i].l]++;out[L[i].r]++;}
}
for(int i=1;i<=n;i++){
num[i]+=num[i-1];
if(abs(num[i])&1){out[i]++;in[i+1]++;add(i+1,i,1);}
}
for(int i=1;i<=n;i++){
if(abs(in[i]-out[i])&1) puts("-1"),exit(0);
if(in[i]>out[i]) add(S,i,(in[i]-out[i])/2),sum+=(in[i]-out[i])/2;
else if(out[i]>in[i]) add(i,T,(out[i]-in[i])/2);
}
memcpy(HD,head,sizeof(head));while(bfs()) sum-=dfs(S,inf);
if(sum) puts("-1"),exit(0);
for(int i=1;i<=m;i++){
if(L[i].k!=-1) printf("%lld ",L[i].k);
else printf("%lld ",edge[id[i]]);
}
return 0;
}
C. 喜欢最最痛
考虑链接了两个点
走这个边就是相当于可以少走两个点之间的路径一遍
于是用树形 \(dp\) 找到带权的直径就行
发现任意两条路径不能有交,否则无法构造一种方案
一开始想的是,把选择的路径都断开,以后不能再走
发现过不去样例,画图发现有这样一种情况
可以断开已经走过的直径,然后分别去匹配新的端点
这样的话原来的贡献就没了,于是把边权变成负的再跑就对了
不会做 \(ddp\) 于是就写的 \(O(nm)\)
Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,ans,mx,x,y;
int fa[100010],dep[100010],f[100010],pos[100010];
int head[100010],ver[200010],to[200010],edge[200010],tot=1;
int vis[100010],now;
priority_queue<int>q;
inline void add(int x,int y,int z){ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;}
void dfs(int x,int fa){
::fa[x]=fa;dep[x]=dep[fa]+1;f[x]=0,pos[x]=x;vis[x]=now;
for(int i=head[x];i;i=to[i]) if(edge[i]){
int y=ver[i];if(y==fa) continue;
dfs(y,x);f[y]+=edge[i];
if(f[x]+f[y]>mx) mx=f[x]+f[y],::x=pos[x],::y=pos[y];
if(f[y]>f[x]) f[x]=f[y],pos[x]=pos[y];
}
if(f[x]>mx) mx=f[x],::x=x,::y=pos[x];
}
inline void del(int x){
for(int i=head[x];i;i=to[i]){
int y=ver[i];
if(y==fa[x]) edge[i]=edge[i^1]=-edge[i];
}
}
inline void upd(int x,int y){
while(dep[x]>dep[y]){del(x);x=fa[x];}
while(dep[y]>dep[x]){del(y);y=fa[y];}
while(x!=y){
del(x);x=fa[x];
del(y);y=fa[y];
}
}
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("love.in","r",stdin);
freopen("love.out","w",stdout);
n=read(),m=read();
for(int i=1,x,y,z;i<n;i++){
x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);ans+=2*z;
}
printf("%lld ",ans);
for(int i=1,a;i<=m;i++){
a=read();mx=0,x=0,y=0;now++;
for(int j=1;j<=n;j++) if(vis[j]!=now) dfs(j,0);
if(q.size()){
if(mx>q.top()){if(mx>a){ans-=mx;ans+=a;q.push(a);upd(x,y);}}
else{if(q.top()>a){ans-=q.top();ans+=a;q.pop();q.push(a);}}
}else if(mx>a){ans-=mx;ans+=a;q.push(a);upd(x,y);}
printf("%lld ",ans);
}
return 0;
}
赛时正序看题,倒序开题, \(T1\) 会了 \(n^6\) 的做法就先跳了
然后先写的 \(T3\) 的暴力,边想边写大概 \(1h\) 把样例过了
正解应该就是用数据结构去维护这个 \(ddp\) 了
于是就去 \(T2\) 了,想着写个退火也许能多搞几分,然后就调了一年
结果最后 \(T1\) 的 \(n^6\) 没调出来就裂开了