• 【模拟赛】纪中提高A组 19.8.23 测试


    Task.1 矩阵乘法

    题目大意:给你一个 (N imes N) 的矩阵,(Q) 次询问每次询问一个子矩形的第 (K) 小数。

    数据范围:(1leq Nleq 500,Qleq 60000)

    树套树(主席树)、整体二分、分块。大概那么搞就能过去...但是我还不是 ds 大师。

    (Source:) 聪明人才能看到的BZOJ 2738 Luogu P1527

    代码:

    Task.2 Tree

    题目大意:给定一张 (n) 个点 (m) 条带权边(权值(c))的连通图,保证存在最小生成树。求最小标准差生成树。

    数据范围:(1leq Nleq 100,N-1leq Mleq 2000,c_ileq 100)

    求最小标准差生成树...就是对于生成树的 (n-1) 条边要最小化这个东西:(sqrt{frac{sum(c_i-overline{c})^2}{n-1}})

    本质上就是最小化 (sum (c_i-overline c)^2)。接下来的操作就比较套路了。

    (f(x)=sum (c_i-x)^2),可以看出这个式子是把 (x) 当平均数对某些 (c_i) 求一个类似方差的东西,当 (x=overline c)(f(x)) 等于上式。

    一种比较初步的思路就是枚举一个 (x) 去求可能的 (c) 有哪些,然后对确定下来的这些 (c) 求标准差。我们把边按照 ((c_i-x)^2) 排序后求“最小”的生成树就能确定 (overline c) 最接近 (x) 时选哪些 (c)能最小化 (f(x)),不停的增加 (x) 同时更新答案即可。

    (Source:) 聪明人才能看到的BZOJ 3754

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    using namespace std;
    
    template<class T>void read(T &x){
    	x=0; char c=getchar();
    	while(c<'0'||'9'<c)c=getchar();
    	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
    }
    typedef double db;
    const int N=105,M=2005;
    
    int n,m;
    int fa[N];
    struct edge{int x,y,c;}e[M];
    int q[N]; db ave,ans=1e9;
    
    db sqr(db x){return x*x;}
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    bool cmp(edge e1,edge e2){return sqr(e1.c-ave)<sqr(e2.c-ave);}
    void kruskal(){
    	int x,y,fx,fy,cnt=0;
    	db tmp=0,sum=0;
    	sort(e+1,e+m+1,cmp);
    	for(int i=1;i<=n;i++)fa[i]=i;
    	for(int i=1;i<=m&&cnt<n;i++){
    		x=e[i].x; y=e[i].y;
    		if((fx=find(x))==(fy=find(y)))continue;
    		fa[fx]=fy; tmp+=e[i].c; q[++cnt]=e[i].c;
    	}
    	if(cnt!=n-1)return ;
    	tmp/=(n-1);
    	for(int i=1;i<n;i++)sum+=sqr(q[i]-tmp);
    	ans=min(ans,sum);
    	return ;
    }
    
    int main(){
    //	freopen("in","r",stdin);
    	read(n); read(m);
    	for(int i=1;i<=m;i++){
    		read(e[i].x); read(e[i].y); read(e[i].c);
    	}
    	for(ave=0.25;ave<=100;ave+=0.25)kruskal();
    	printf("%.4lf
    ",sqrt(ans/(n-1)));
    	return 0;
    }
    

    Task.3 Points and Segments

    题目大意:在数轴上有 (n) 条线段([l,r]),现在要把每条线段染成红色或蓝色。求一个满足数轴上所有点被两种颜色的线段覆盖次数 (|c_{red}-c_{blue}|leq 1)的一种合法的染色方案。

    数据范围:(1leq Nleq 10^5,0leq l_i,r_ileq 10^9)

    吓死我了我还以为要求方案数

    可以想到把染两种颜色分别看做 (+1 -1),然后就是求区间加减之后结果每个位置绝对值不超过 (1)

    然后还有一种想法是离散后建图,连接 (l_i,r_i) ,然后让每个位置被尽可能相等的两种颜色的边覆盖。

    如果把两种思路结合一下,把建的边看成有权值的。分配权值的方法就是给边定向。就是要平衡一个点往左往右的边数。从一个点出发向一个方向走过去,再回来...若能平衡这个次数,我们就一定能找到一种定向方案。

    回路?什么回路?我们发现这个东西有点像欧拉回路。

    若建好图图中没有奇点的话,欧拉回路一定存在,那么我们就可以构造出一种合法方案。

    若存在奇点。那么奇点的个数一定是偶数个(想想为什么)。我们从左到右枚举每一个奇点,和他之后最近的一个奇点连边把他们俩都变成偶点,再往后跳,这样就能变成上面的那种情况,再求解欧拉回路就可以了。至于奇点之间连的那些边删掉也不会使答案变得不合法(想想为什么)。

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    template<class T>void read(T &x){
    	x=0; char c=getchar();
    	while(c<'0'||'9'<c)c=getchar();
    	while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
    }
    
    const int N=200050;
    
    int n;
    struct seg{int l,r;}a[N];
    int t[N],cnt;
    int d[N],ans[N];
    int head[N],tot=1,pos[N];
    struct edge{int to,next;}e[N<<1];
    int vis[N],ve[N];
    
    void add(int x,int y){e[++tot]=(edge){y,head[x]}; head[x]=tot;}
    void dfs(int x,int dep=1){
    	vis[x]=1;
    	for(int i=head[x],y;i;i=e[i].next){
    		y=e[i].to; if(ve[i>>1])continue;
    		ve[i>>1]=1; ans[pos[i>>1]]=x<y;
    		dfs(y);
    	}
    }
    
    int main(){
    //	freopen("in","r",stdin);
    	read(n);
    	int x,y;
    	for(int i=1;i<=n;i++){
    		read(x); read(y); ++y;
    		a[i]=(seg){x,y};
    		t[++cnt]=x; t[++cnt]=y;
    	}
    	sort(t+1,t+cnt+1);
    	cnt=unique(t+1,t+cnt+1)-t-1;
    	for(int i=1;i<=n;i++){
    		x=lower_bound(t+1,t+cnt+1,a[i].l)-t;
    		y=lower_bound(t+1,t+cnt+1,a[i].r)-t;
    		++d[x]; ++d[y];
    		add(x,y); add(y,x);
    		pos[tot>>1]=i;
    	}
    	for(x=1,y=-1;x<=cnt;x++)if(d[x]&1){
    		if(y==-1)y=x;
    		else {add(x,y); add(y,x); y=-1;}
    	}
    	for(x=1;x<=cnt;x++)
    		if(!vis[x])dfs(x);
    	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    洛谷 P1080 [NOIP2012 提高组] 国王游戏
    洛谷 P4370 [Code+#4]组合数问题2
    洛谷 P4369 [Code+#4]组合数问题
    洛谷 P3311 [SDOI2014] 数数
    implicit关键字详解
    模式匹配
    option[T]、Any、Nothing、Null类型的介绍
    高阶函数
    函数的介绍
    集合
  • 原文地址:https://www.cnblogs.com/opethrax/p/11402427.html
Copyright © 2020-2023  润新知