• 202286 #23 UNR#6 Day1


    昨天毒奶了一口比 hzr 少一题,今天打完发现和 hzr 题数相等,结果 fst 了(

    057 uoj#747. 【UNR #6】面基之路

    一开始猜了个结论,后来发现是极为显然的。

    一定存在一种最优方案使得所有人最后在同一位置,因为见面了之后可以让网友一直跟着 hehe 蚤到最后面基。

    于是枚举一下在哪个位置面基,点上很容易考虑,边上需要考虑哪些网友从 \(x\) 进入,哪些网友从 \(y\) 进入,答案是一个关于从 \(x\) 进入时间最大值,从 \(y\) 进入时间最大值的式子,枚举一下就好了。

    复杂度 \(O(nk\log n+mk\log k)\)

    比赛的时候和 myy 想的一样,以为贪心地将离 \(x\) 近的分配给 \(x\) 是对的,拍了一千多组没过就丢一边了。。。

    #include<stdio.h>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int maxn=100005,maxm=200005,maxk=25;
    const long long inf=1e18;
    int n,m,k;
    long long ans;
    long long dis[maxk][maxn];
    int p[maxk],vis[maxn],xx[maxm],yy[maxm],zz[maxm];
    vector<int>v[maxn],w[maxn];
    priority_queue< pair<long long,int> >q;
    void dijkstra(int id,int s){
    	for(int i=1;i<=n;i++)
    		dis[id][i]=inf,vis[i]=0;
    	dis[id][s]=0,q.push(make_pair(0,s));
    	while(!q.empty()){
    		int x=q.top().second;
    		q.pop();
    		if(vis[x])
    			continue;
    		vis[x]=1;
    		for(int i=0;i<v[x].size();i++){
    			int y=v[x][i],z=w[x][i];
    			if(dis[id][y]>dis[id][x]+z)
    				dis[id][y]=dis[id][x]+z,q.push(make_pair(-dis[id][y],y));
    		}
    	}
    }
    struct limit{
    	long long l,r;
    }t[maxk];
    inline int cmp(limit a,limit b){
    	return a.l>b.l||(a.l==b.l&&a.r<b.r);
    }
    inline void chk(long long mx0,long long mx1,int z){
    	long long v=min(max(0ll,mx1-mx0+z),0ll+z+z);
    	ans=min(ans,max(mx0+mx0+v,mx1+mx1+z+z-v));
    }
    int main(){
    //	freopen("A.in","r",stdin);
    //	freopen("A.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(int i=1,x,y,z;i<=m;i++){
    		scanf("%d%d%d",&x,&y,&z),v[x].push_back(y),v[y].push_back(x);
    		w[x].push_back(z),w[y].push_back(z),xx[i]=x,yy[i]=y,zz[i]=z;
    	}
    	scanf("%d",&k),dijkstra(0,1);
    	for(int i=1;i<=k;i++)
    		scanf("%d",&p[i]),dijkstra(i,p[i]);
    	ans=1e18;
    	for(int i=1;i<=n;i++){
    		long long res=0;
    		for(int j=0;j<=k;j++)
    			res=max(res,dis[j][i]);
    		ans=min(ans,res+res);
    	}
    	for(int i=1;i<=m;i++){
    		int x=xx[i],y=yy[i],z=zz[i];
    		for(int j=0;j<=k;j++)
    			t[j]=limit{dis[j][x],dis[j][y]};
    		sort(t,t+1+k,cmp);
    		long long mx=0;
    		for(int j=0;j<=k;j++)
    			chk(t[j].l,mx,z),mx=max(mx,t[j].r);
    		chk(0,mx,z);
    	}
    	printf("%lld\n",ans);
    	return 0;
    }
    

    058 uoj#748. 【UNR #6】机器人表演

    抱着一个假做法写了好久,最后发现怎么计数都会重。重构做法之后编了好久才过。。。

    而此时 hzr 早就过了,orz hzr。

    首先给出合法串的判定方式:存在去掉一个为 \(S\) 子序列的方式,使得剩下的串将 \(0,1\) 分别视作 \((,)\) 后为合法括号串。

    一个很显然的错误想法是钦定去掉最靠前的匹配子序列。给出一组 hack:0010。(原串为 00

    我们考虑在 dp 过程中修正这一错误,当我们加入一个 1 使得括号序列不合法时,我们将当前匹配子序列最靠后的和为 \(1\) 的后缀补偿给括号序列,预处理这个位置即可做到 \(O(nt(n+t))\)

    其实我也不会很严谨地证明这一过程,但是可以发现每次补偿完,前缀和都会到达 \(0\),因此我们钦定的子序列是下标对应子序列字典序最小的子序列,不重不漏。

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=305,mod=998244353;
    int n,t,ans;
    int f[maxn][maxn],g[maxn][maxn],pre[maxn];
    string s;
    inline int inc(int x){
    	return x>=mod? x-mod:x;
    }
    int main(){
    //	freopen("B.in","r",stdin);
    //	freopen("B.out","w",stdout);
    	scanf("%d%d",&n,&t),cin>>s,s=s+" ";
    	pre[0]=-1;
    	for(int i=1;i<=n;i++){
    		int cnt=0;
    		pre[i]=-1;
    		for(int j=i-1;j>=0;j--){
    			cnt+=s[j]=='0'? 1:-1;
    			if(cnt==1){
    				pre[i]=j;
    				break;
    			}
    		}
    	}
    	f[0][0]=1;
    	for(int i=0;i<n+t+t;i++){
    		for(int j=0;j<=n;j++)
    			for(int k=0;k<=t;k++)
    				if(f[j][k]){
    //					printf("i=%d j=%d k=%d p=%d\n",i,j,k,p);
    					int p=f[j][k];
    					if(j<n)
    						g[j+1][k]=inc(g[j+1][k]+p);
    					if(s[j]!='0')
    						g[j][k+1]=inc(g[j][k+1]+p);
    					if(s[j]!='1'){
    						if(k>0)
    							g[j][k-1]=inc(g[j][k-1]+p);
    						else if(pre[j]!=-1)
    							g[pre[j]][0]=inc(g[pre[j]][0]+p);
    					}
    				}
    		for(int j=0;j<=n;j++)
    			for(int k=0;k<=t;k++)
    				f[j][k]=g[j][k],g[j][k]=0;
    	}
    	printf("%d\n",f[n][0]);
    	return 0;
    }
    

    059 uoj#749. 【UNR #6】稳健型选手

    应该做出来的,可惜了。

    一个比较简单的想法是反悔贪心,从左到右,奇数位置加入堆,然后每个位置检查是否比能替代堆中的最小值。

    这一贪心也可以类似地做到从右到左,奇数位置将堆中的最大值计入答案就好了。

    对询问猫树分治,问题在于二区间合并,方案的变化实际上是很好刻画的,无非是从左区间取出 \(k\) 个选了的位置来换右区间 \(k\) 个没选的位置。

    主席树上二分即可,复杂度 \(O(n\log^2 n+q\log n)\)

    #include<stdio.h>
    #include<vector>
    #include<queue>
    using namespace std;
    const int maxn=200005,maxt=maxn*60,V=1000000000;
    int n,m,tot;
    int a[maxn],id[maxn],qx[maxn],qy[maxn],tmp[maxn],rt[maxn],lc[maxt],rc[maxt],sz[maxt];
    long long ans[maxn],sum[maxt];
    vector<int>v[maxn];
    priority_queue<int>q;
    void modify(int l,int r,int &now,int p){
    	tot++,lc[tot]=lc[now],rc[tot]=rc[now],sz[tot]=sz[now]+1,sum[tot]=sum[now]+p,now=tot;
    	if(l==r)
    		return ;
    	int mid=(l+r)>>1;
    	if(p<=mid)
    		modify(l,mid,lc[now],p);
    	else modify(mid+1,r,rc[now],p);
    }
    long long query(int l,int r,int a,int b,int u,int v){
    	if(l==r)
    		return 1ll*(u-v)*l;
    	int mid=(l+r)>>1,nu=u+sz[lc[a]],nv=v+sz[rc[b]];
    	if(nu<nv)
    		return query(mid+1,r,rc[a],rc[b],nu,v)-sum[lc[a]];
    	if(nu>nv)
    		return query(l,mid,lc[a],lc[b],u,nv)+sum[rc[b]];
    	return sum[rc[b]]-sum[lc[a]];
    }
    void solve(int l,int r,int ql,int qr){
    	if(l==r){
    		for(int i=ql;i<=qr;i++)
    			ans[id[i]]=a[l];
    		return ;
    	}
    	int mid=(l+r)>>1,nql=ql-1,nqr=qr+1;
    	for(int i=mid+1;i<=r;i++){
    		vector<int>_;
    		_.swap(v[i]);
    	}
    	for(int i=ql;i<=qr;i++){
    		if(qy[id[i]]<=mid)
    			tmp[++nql]=id[i];
    		else if(qx[id[i]]>mid)
    			tmp[--nqr]=id[i];
    		else v[qy[id[i]]].push_back(id[i]);
    	}
    	for(int i=ql;i<=qr;i++)
    		id[i]=tmp[i];
    	for(int o=0;o<=1;o++){
    		tot=lc[0]=rc[0]=sum[0]=sz[0]=0;
    		while(!q.empty())
    			q.pop();
    		for(int i=mid;i>=l;i--){
    			rt[i]=i==mid? 0:rt[i+1],q.push(a[i]);
    			if((i&1)==o)
    				modify(1,V,rt[i],q.top()),q.pop();
    		}
    		while(!q.empty())
    			q.pop();
    		long long now=0;
    		for(int i=mid+1;i<=r;i++){
    			rt[i]=i==mid+1? 0:rt[i-1],now+=a[i],q.push(-a[i]);
    			if((i&1)!=o)
    				now+=q.top(),modify(1,V,rt[i],-q.top()),q.pop();
    			for(int j=0;j<v[i].size();j++){
    				int k=v[i][j],x=qx[k],y=qy[k];
    				if((x&1)==o)
    					ans[k]=sum[rt[x]]+now+query(1,V,rt[x],rt[i],0,0);
    			}
    		}
    	}
    	if(ql<=nql)
    		solve(l,mid,ql,nql);
    	if(nqr<=qr)
    		solve(mid+1,r,nqr,qr);
    }
    int main(){
    //	freopen("C.in","r",stdin);
    //	freopen("C.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++)
    		scanf("%d%d",&qx[i],&qy[i]),id[i]=i;
    	solve(1,n,1,m);
    	for(int i=1;i<=m;i++)
    		printf("%lld\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    mybatis 动态sql
    linux shell 之 crontab(定时任务)详解
    FTP定时批量下载文件(SHELL脚本及使用方法 )
    腾讯云数据库团队:MySQL5.7 JSON实现简单介绍
    Chisel Tutorial(七)——模块
    大数问题解决模板
    可靠的功能測试--Espresso和Dagger2
    hdoj 1698 Just a Hook 【线段树 区间更新】
    平衡二叉树
    WPF中DependencyObject与DependencyProperty的源代码简单剖析
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/16558020.html
Copyright © 2020-2023  润新知