zoukankan      html  css  js  c++  java
  • 模拟赛 10-20考试记

    10-20考试记

    预期得分245,实际得分245。

    第三题一看暴力那么好玩,直接各种分段暴力真开心。

    rank_2,%%%AK大佬C。

    第三题是很好的题嘞。

    1、求助

    (help.cpp/c/pas)

    【问题背景】

    马上就要noip了,lrt同志(displaystyleegin{vmatrix} extrm{慌}&sqrt{ extrm{批}}\sqrt{ extrm{批}}& extrm{的}end{vmatrix}=慌得一批),在某个透彻的晚四,找rqj整理OI知识点

    【问题描述】

    $ $rqj可是个dalao,他有一个神奇的技能,可以把两个毫无关系的知识点完美的联系在一起,耗费时间 (T_i), lrt表示不服,但是他必须花好长时间才能做到,一次耗时(t_i (t_i>T_i)),对于整个OI知识网络,共有m种联系,每一种可以将两个知识点相连,现在二人要把整个OI知识联系起来,为了锻炼lrt,lrt必须自己想至少k个联系,但rqj日理万机,耐心有限,他希望这几次联系中,时间最长的那次联系的时间最小,但是rqj懒的算QAQ,于是来请聪明的你帮他算一算

    【输入】

    输入文件名(help.in)

    第一行为三个整数(n,k,m),n为知识点数,m为联系个数,k如上述所示

    接下来(m)行,每行四个整数(x_i y_i T_i t_i),

    【输出】

    输出仅一行,为最长联系时间的最小值

    直接二分答案,每一次用克鲁斯卡尔判断图的连通性就好了。全场切?

    code:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int wx=2000017;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    	return sum*f;
    }
    
    int fa[wx],head=0x3f3f3f3f,tail=-0x3f3f3f3f;
    int n,m,k,ans=0;
    
    struct node{
    	int x,y,d;
    	friend bool operator < (const node & a,const node & b){
    		return a.d<b.d;
    	}
    }t1[wx],t2[wx];
    
    int find(int x){
    	if(fa[x]==x)return x;
    	return fa[x]=find(fa[x]);
    }
    
    void pre(){
    	for(int i=1;i<=n;i++)fa[i]=i;
    }
    
    bool ok(int now){
    	int l=1,r=m;
    	int tot=0;
    	while(l<=r){
    		int mid=l+r>>1;
    		if(t2[mid].d<=now)tot=mid,l=mid+1;
    		else r=mid-1;
    	}
    	if(tot<k)return false;
    	pre();
    	int zmj=0;
    	for(int i=1;i<=m;i++){
    		if(t2[i].d>now)break;
    		int fx=find(t2[i].x); int fy=find(t2[i].y);
    		if(fx==fy)continue;
    		fa[fx]=fy; zmj++;
    		if(zmj>=n-1)return true;
    	}
    	for(int i=1;i<=m;i++){
    		if(t1[i].d>now)break;
    		int fx=find(t1[i].x); int fy=find(t1[i].y);
    		if(fx==fy)continue;
    		fa[fx]=fy; zmj++;
    		if(zmj>=n-1)return true;
    	}
    	return false;
    }
    
    int main(){
    	freopen("help.in","r",stdin);
    	freopen("help.out","w",stdout);
    	
    	n=read(); k=read(); m=read();
    	for(int i=1;i<=m;i++){
    		int x,y; x=read(); y=read(); t1[i].d=read(); t2[i].d=read();
    		t1[i].x=t2[i].x=x;
    		t1[i].y=t2[i].y=y;
    		head=min(head,min(t1[i].d,t2[i].d));
    		tail=max(tail,max(t1[i].d,t2[i].d));
    	}
    	sort(t1+1,t1+1+m);
    	sort(t2+1,t2+1+m);
    	while(head<=tail){
    		int mid=head+tail>>1;
    		if(ok(mid))ans=mid,tail=mid-1;
    		else head=mid+1;
    	}
    	printf("%d
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
    /*
    4 2 5 
    1 2 5 6 
    1 3 1 3 
    2 3 4 9 
    2 4 1 6 
    3 4 2 4
    */
    

    2、心动

    (olinr.cpp/c/pas)

    【问题背景】

    透彻人不干氨醛事,olinr走上了一条不归路

    【问题描述】

    $ $olinr很喜欢TA,但是在二中的压迫下,透彻需谨慎,他必须合理安排在一起的时间,olinr和TA在不同
    的教学楼,每天都要去不同的canteen打饭,他希望节约时间的前提下在一起走路的时间尽量长。

    $ $现在已知二人的教学楼和两个目标canteen还有二中的地图,有n个路口,m条路,每条路经过需要一
    定的时间。

    $ $一句话概括题意:给出两个起点,终点,求最短路的最长公共路径

    【输入】

    输入文件名(olinr.in)

    第一行为两个整数(n , m),分别表示点数和边数

    第二行为四个整数(x_1 y_1 x_2 y_2) 分别表示两个教学楼和食堂的编号(x_1 o y_1 x_2 o y_2)

    接下来(m)行,每行三个整数(x_i y_i z_i) ,表示(x_i)(y_i)有一条长度为(z_i)的边

    【输出】

    输出仅一行,为最长公共路径

    挺模板的一道题吧,两边SPFA标记好最短路上的边转移就好。

    学长用枚举点对的(n^2)做法怒切,%%%。

    code:

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    
    #define int long long
    
    using namespace std;
    
    const int wx=1978;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    	return sum*f;
    }
    
    int num=1;
    int n,m,val;
    int sx,tx,sy,ty;
    
    int head[wx],dis[wx],vis[wx];
    int ans[wx],zmj[wx];
    
    struct e{
    	int nxt,to,dis,flag;
    }edge[wx*wx];
    
    void add(int from,int to,int dis){
    	edge[++num].nxt=head[from];
    	edge[num].to=to;
    	edge[num].dis=dis;
    	head[from]=num;
    }
    
    queue<int > q;
    void jiade_Dij(int s){
    	for(int i=1;i<=n;i++)dis[i]=0x3f3f3f3f,vis[i]=0;
    	q.push(s);dis[s]=0;vis[s]=1;
    	while(q.size()){
    		int u=q.front(); q.pop(); vis[u]=0;
    		for(int i=head[u];i;i=edge[i].nxt){
    			int v=edge[i].to;
    			if(dis[v]>dis[u]+edge[i].dis){
    				dis[v]=dis[u]+edge[i].dis;
    				if(!vis[v]){
    					vis[v]=1; q.push(v);
    				}
    			}
    		}
    	}
    }
    
    void bfs(){
    	q.push(sy); memset(vis,0,sizeof vis);
    	vis[sy]=1;
    	while(q.size()){
    		int u=q.front(); q.pop();
    		for(int i=head[u];i;i=edge[i].nxt){
    			int v=edge[i].to;
    			if(dis[v]+edge[i].dis==dis[u]){
    				edge[i].flag=1;
    				edge[i^1].flag=1;
    				if(!vis[v]){
    					vis[v]=1; q.push(v);
    				}
    			}
    		}
    	}
    }
    
    void work(){
    	memset(vis,0,sizeof vis);
    	vis[ty]=1; zmj[ty]=1; q.push(ty);
    	while(q.size()){
    		int u=q.front(); q.pop(); vis[u]=0;
    		for(int i=head[u];i;i=edge[i].nxt){
    			int v=edge[i].to;
    			if(dis[v]+edge[i].dis==dis[u]){
    				if(edge[i].flag&&ans[v]<ans[u]+edge[i].dis){
    					ans[v]=ans[u]+edge[i].dis;
    					val=max(val,ans[v]);
    					if(!vis[v]){
    						vis[v]=1;
    						q.push(v);
    					}
    				}
    				if(!zmj[v]){
    					vis[v]=1;
    					zmj[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    }
    
    signed main(){
    //	freopen("olinr.in","r",stdin);
    //	freopen("olinr.out","w",stdout);
    	
    	n=read(); m=read();
    	sx=read(); sy=read(); tx=read(); ty=read();
    	for(int i=1;i<=m;i++){
    		int x,y,z;
    		x=read(); y=read(); z=read();
    		add(x,y,z); add(y,x,z);
    	}
    	jiade_Dij(sx);
    	bfs();
    	jiade_Dij(tx);
    	work();
    	printf("%lld
    ",val);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    3、透彻

    (game.cpp/c/pas)

    【问题背景】

    奥赛部终于放假了, 像olinr这种人,当然选择透彻啦!

    【问题描述】

    $ $olinr正在卧室的电脑前透彻。。。

    $ $olinr打算通关一个游戏,从而获得金币买装备。这个游戏有n个场景,有许多通关途径。具体来说,某些场景

    可以通过分支到达其它场景,这些场景构成了一棵树。olinr此时在根节点,他要到叶子节点即可通关。每个场景

    都有一些金币,olinr可以获得它们。由于太久没放假,olinr积累了大量的能力值,使得他可以同时通关(k)次,当

    然,同一个场景再次走到就没有金币了QAQ(一个场景的金币只能获得一次),不过偷车时间宝贵,他急忙问

    你,他最多能获得多少金币,你要在(1s) 内告诉他欧(1号节点为根节点)

    【输入】

    输入文件名game.in$

    第一行为两个整数(n , k),分别表示点数和次数

    第二行为(n)个整数,分别表示每个场景的金币数量

    接下来(n-1)行,每行两个整数(x_i y_i) ,表示(x_i)场景有一个分支通向(y_i)场景

    【输出】

    输出仅一行,为最大金币获得数量

    考场上把45分暴力全拿了,都把我给写high了,但就是忘记想正解了。(其实不会)。

    其实也很简单。 首先一直拿当前最大的的贪心是很容易证的。

    问题就是每一次找到这个当前局面最大的。

    考场上直接想的暴力。

    也很容易想到用数据结构维护,那么用dfn序建树,维护区间最大值和最大值的位置,那么每一次更新之后可以直接查询(t(1))的信息就好了。

    个人感觉很好想,但是说不明白,哎呀不说了,直接上代码。

    code:

    #include <iostream>
    #include <cstdio>
    
    #define int long long
    
    #define ls(o) o<<1
    #define rs(o) o<<1|1
    
    using namespace std;
    
    const int wx=1000177;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    	return sum*f;
    }
    
    int num,n,k,ans,tot;
    int vis[wx],tid[wx];
    int head[wx],dfn[wx],size[wx],a[wx],f[wx];
    
    struct val_tree{
    	int l,r,ma,tag,pos;
    	#define ma(o) t[o].ma
    	#define tag(o) t[o].tag
    	#define pos(o) t[o].pos
    }t[wx*2];
    
    struct node{
    	int pos,ma;
    };
    
    void up(int o){
    	if(ma(ls(o))>=ma(rs(o))){
    		ma(o)=ma(ls(o)); pos(o)=pos(ls(o));
    	}
    	else ma(o)=ma(rs(o)),pos(o)=pos(rs(o));
    }
    
    void down(int o){
    	if(tag(o)){
    		ma(ls(o))+=tag(o); ma(rs(o))+=tag(o);
    		tag(ls(o))+=tag(o); tag(rs(o))+=tag(o);
    		tag(o)=0;
    	}
    }
    
    void build(int o,int l,int r){
    	t[o].l=l; t[o].r=r;
    	if(l==r){pos(o)=l;return ;}
    	int mid=t[o].l+t[o].r>>1;
    	if(l<=mid)build(ls(o),l,mid);
    	if(r>mid)build(rs(o),mid+1,r);
    	up(o);
    }
    
    void update(int o,int l,int r,int k){
    	if(l<=t[o].l&&t[o].r<=r){
    		ma(o)+=k; tag(o)+=k; return ;
    	}
    	down(o); 
    	int mid=t[o].l+t[o].r>>1;
    	if(l<=mid)update(ls(o),l,r,k);
    	if(r>mid)update(rs(o),l,r,k);
    	up(o);
    }
    
    struct e{
    	int nxt,to;
    }edge[wx*2];
    
    void add(int from,int to){
    	edge[++num].nxt=head[from];
    	edge[num].to=to;
    	head[from]=num;
    }
    
    void dfs(int u,int fa){
    	f[u]=fa; dfn[u]=++tot; tid[tot]=u; size[u]=1;
    	for(int i=head[u];i;i=edge[i].nxt){
    		int v=edge[i].to;
    		if(v==fa)continue;
    		dfs(v,u); size[u]+=size[v];
    	}
    }
    
    void dfs_wx(int u){
    	while(!vis[u]&&u){
    		update(1,dfn[u],dfn[u]+size[u]-1,-a[u]);
    		vis[u]=1;
    		u=f[u];
    	}
    }
    
    signed main(){
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	n=read(); k=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<n;i++){
    		int x,y;
    		x=read(); y=read();
    		add(x,y); add(y,x);
    	}
    	dfs(1,0); build(1,1,n);
    	for(int i=1;i<=n;i++)update(1,dfn[i],dfn[i]+size[i]-1,a[i]);
    	while(k--){
    		node tmp=(node){t[1].pos,t[1].ma}; 
    		ans+=tmp.ma; int pos=tmp.pos;
    		dfs_wx(tid[pos]);
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    继续加油。

  • 相关阅读:
    wampserver服务器离线,无法访问此网站 找不到 项目 的服务器 DNS 地址。
    node.js(一)介绍与安装
    js全局函數
    类和对象的定义
    iframe框架学习
    while和do-while的区别
    html5视频音频
    列表
    html表格的学习
    云课堂数组1
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9822044.html
Copyright © 2011-2022 走看看