2022-8-9 #24 CF1408H & CF1696G & AGC043F
摆。
有同学给我推荐了音游,玩了一下,非常好玩啊!(所以这就是你不更博的理由吗
060 CF1408H Rainbow Triples
第一眼就可以想到一个网络流模型:将 \(0\) 向后面的 \(b_i\) 连边,\(b_i\) 向后面的 \(0\) 连边。问题在于怎么钦定哪些 \(0\) 连入,哪些 \(0\) 连出。
由于答案上界是 \(0\) 的数量 \(z\) 除二,可以钦定前一半 \(0\) 连入,后一半 \(0\) 连出,显然仍然正确。
对于一种颜色,我们找到这个颜色最靠前、最靠后的两个位置 \(u,v\),于是我们可以将连边刻画成 \(S\rightarrow c,c\rightarrow[1,\min(u,\lfloor\frac z2\rfloor)],c\rightarrow [\max(v,\lceil\frac z2\rceil)+1,z]\)。
前缀后缀连边可以使用前缀和,令前一半的 \(0\) 从后往前连边,后一半的 \(0\) 从前往后连边,那么问题就变成了求这张图的最大流。
最大流转最小割,于是一个颜色不割,就要割对应的前缀和后缀所有点。
从后往前枚举前缀割了多长,用线段树维护每个后缀割的长度对应答案,复杂度 \(O(n\log n)\)。
#include<stdio.h>
#include<vector>
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
#define mid (l+r>>1)
using namespace std;
const int maxn=500005,maxt=maxn<<2;
int T,n,z,ans;
int a[maxn],l[maxn],r[maxn],lazy[maxt],mn[maxt];
vector<int>v[maxn];
inline void pushup(int now){
mn[now]=min(mn[lc(now)],mn[rc(now)]);
}
inline void getlazy(int now,int v){
lazy[now]+=v,mn[now]+=v;
}
inline void pushdown(int now){
if(lazy[now])
getlazy(lc(now),lazy[now]),getlazy(rc(now),lazy[now]),lazy[now]=0;
}
void build(int l,int r,int now){
lazy[now]=0;
if(l==r){
mn[now]=l+n;
return ;
}
build(l,mid,lc(now)),build(mid+1,r,rc(now)),pushup(now);
}
void update(int l,int r,int now,int L,int R,int v){
if(L<=l&&r<=R){
getlazy(now,v);
return ;
}
pushdown(now);
if(L<=mid)
update(l,mid,lc(now),L,R,v);
if(mid<R)
update(mid+1,r,rc(now),L,R,v);
pushup(now);
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n),z=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),z+=a[i]==0;
for(int i=1;i<=n;i++)
l[i]=r[i]=0;
int now=0;
for(int i=1;i<=n;i++){
if(a[i]==0)
now++;
else if(now<=z/2)
l[a[i]]=max(l[a[i]],now);
}
now=0;
for(int i=n;i>=1;i--){
if(a[i]==0)
now++;
else if(now<=z/2)
r[a[i]]=max(r[a[i]],now);
}
build(0,z/2,1);
for(int i=1;i<=n;i++)
v[l[i]].push_back(r[i]);
ans=1e9;
for(int i=0;i<=z/2;i++){
for(int j=0;j<v[i].size();j++)
update(0,z/2,1,v[i][j],z/2,-1);
v[i].clear();
ans=min(ans,mn[1]+i);
}
printf("%d\n",min(z/2,ans));
}
return 0;
}
061 CF1696G Fishingprince Plays With Array Again
之后再写。
#include<stdio.h>
#include<string.h>
#include<iostream>
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
#define mid (l+r>>1)
using namespace std;
const int maxn=200005,maxt=maxn<<2;
int n,m,x,y;
int a[maxn];
struct matrix{
int len,wid;
double a[4][4];
matrix operator *(matrix p){
matrix res;
res.len=len,res.wid=p.wid;
for(int i=1;i<=res.len;i++)
for(int j=1;j<=res.wid;j++)
res.a[i][j]=-1e18;
for(int i=1;i<=len;i++)
for(int j=1;j<=p.wid;j++)
for(int k=1;k<=wid;k++)
res.a[i][j]=max(res.a[i][j],a[i][k]+p.a[k][j]);
return res;
}
}st,t[maxt],trans;
inline void setval(int p,int now){
t[now].len=t[now].wid=3,t[now].a[1][1]=0,t[now].a[2][2]=1.0*a[p]/x,t[now].a[3][3]=1.0*a[p]/(x+y);
}
inline void pushup(int now){
t[now]=t[lc(now)]*trans*t[rc(now)];
}
void build(int l,int r,int now){
if(l==r){
setval(l,now);
return ;
}
build(l,mid,lc(now)),build(mid+1,r,rc(now)),pushup(now);
}
void modify(int l,int r,int now,int p){
if(l==r){
setval(l,now);
return ;
}
if(p<=mid)
modify(l,mid,lc(now),p);
else modify(mid+1,r,rc(now),p);
pushup(now);
}
matrix query(int l,int r,int now,int L,int R){
if(L<=l&&r<=R)
return t[now];
if(L<=mid&&mid<R)
return query(l,mid,lc(now),L,R)*trans*query(mid+1,r,rc(now),L,R);
if(L<=mid)
return query(l,mid,lc(now),L,R);
return query(mid+1,r,rc(now),L,R);
}
int main(){
st.len=1,st.wid=3;
trans.len=trans.wid=3,trans.a[2][2]=trans.a[2][3]=trans.a[3][2]=-1e18;//0 1/x 1/(x+y)
scanf("%d%d%d%d",&n,&m,&x,&y);
if(x<y)
swap(x,y);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,n,1);
for(int i=1,t,x,y;i<=m;i++){
scanf("%d%d%d",&t,&x,&y);
if(t==1)
a[x]=y,modify(1,n,1,x);
if(t==2){
matrix res=st*query(1,n,1,x,y);
double ans=0;
for(int i=1;i<=3;i++)
ans=max(ans,res.a[1][i]);
printf("%.10lf\n",ans);
}
}
return 0;
}
062 AGC043F Jewelry Box
之后再写。
#include<stdio.h>
#include<queue>
#include<vector>
#include<algorithm>
#define inf 1000000000000000000
#define INF 100000
using namespace std;
const int maxn=1005,maxm=10005;
int n,m,Q,e=1,flow,tot,s,t;
int start[maxn],to[maxm],then[maxm],limit[maxm],mn[maxn],vis[maxn],rec[maxn];
int K[maxn],sum[maxn];
long long cost;
long long dis[maxn],worth[maxm],res[3][maxn];
queue<int>q;
inline void add(int x,int y,int z,long long w){
then[++e]=start[x],start[x]=e,to[e]=y,limit[e]=z,worth[e]=w;
}
inline void addedge(int x,int y,int z,long long w){
add(x,y,z,w),add(y,x,0,-w);
}
int spfa(int s,int t){
for(int i=1;i<=t;i++)
dis[i]=inf,vis[i]=rec[i]=0;
while(!q.empty())
q.pop();
dis[s]=0,vis[s]=1,mn[s]=INF,q.push(s);
while(!q.empty()){
int x=q.front();
vis[x]=0,q.pop();
for(int i=start[x];i;i=then[i]){
int y=to[i];
long long z=worth[i];
if(limit[i]&&dis[y]>dis[x]+z){
dis[y]=dis[x]+z,rec[y]=i,mn[y]=min(mn[x],limit[i]);
if(vis[y]==0)
q.push(y),vis[y]=1;
}
}
}
return rec[t]!=0;
}
void work(int s,int t){
cost+=dis[t]*mn[t],flow+=mn[t];
for(int i=t;i!=s;i=to[rec[i]^1])
limit[rec[i]]-=mn[t],limit[rec[i]^1]+=mn[t];
}
struct jew{
long long s,c;
int p;
bool operator <(const jew &t)const{
return s<t.s||(s==t.s&&p<t.p);
}
}w[maxn];
int main(){
scanf("%d",&n);
for(int i=1,k;i<=n;i++){
scanf("%d",&k),sum[i+1]=sum[i]+k,K[i]=k;
for(int j=1;j<=k;j++)
scanf("%lld%d%lld",&w[sum[i]+j].s,&w[sum[i]+j].p,&w[sum[i]+j].c);
sort(w+sum[i]+1,w+sum[i]+k+1);
}
s=sum[n+1]+1,t=s+1;
for(int i=1;i<=n;i++){
int lst=s;
for(int j=1;j<=K[i];j++){
addedge(sum[i]+j,lst,INF,0),addedge(lst,sum[i]+j,INF,w[sum[i]+j].c);
addedge(lst,sum[i]+j,w[sum[i]+j].p,0),lst=sum[i]+j;
}
addedge(sum[i]+K[i],t,INF,0),addedge(t,sum[i]+K[i],INF,0);
}
scanf("%d",&m);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
for(int j=sum[x]+1;j<=sum[x]+K[x];j++){
int p=lower_bound(w+sum[y]+1,w+sum[y]+K[y]+1,jew{w[j].s+z+1,0,0})-w;
if(p==sum[y]+1)
addedge(s,j,INF,0);
else addedge(p-1,j,INF,0);
}
}
while(spfa(s,t)){
tot++,res[0][tot]=dis[t],work(s,t),res[1][tot]=flow,res[2][tot]=cost;
if(flow>=INF)
break;
}
scanf("%d",&Q);
while(Q--){
long long x;
scanf("%lld",&x);
int p=(lower_bound(res[0]+1,res[0]+1+tot,x)-res[0]);
if(p>tot)
puts("-1");
else printf("%lld\n",x*res[1][p-1]-res[2][p-1]);
}
return 0;
}