2019.08.23【NOIP提高组】模拟 A 组

洛谷 1527 JZOJ 2908 矩阵乘法

题目

给定一个矩阵,多组询问子矩阵的第 k k k大,不带修改


分析

这是一道整体二分的好题,以矩阵的 n 2 n^2 n2为值域,用二维树状数组记录 ≤ m i d \leq mid mid的个数
时间复杂度 O ( Q l o g 4 n ) O(Qlog^4n) O(Qlog4n),然而常数很小


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=20011;
struct rec{int x1,y1,x2,y2,w,rk;}q[N<<4],q1[N<<4],q2[N<<4];
int c[501][501],n,m,tot,ans[N*3],b[N*13],cnt;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void add(int x,int y,int z){
	rr int y1=y;
	for (;x<=n;x+=-x&x)
	for (y=y1;y<=n;y+=-y&y) c[x][y]+=z;
}
inline signed query(int x,int y){
	rr int y1=y,ans=0;
	for (;x;x-=-x&x)
	for (y=y1;y;y-=-y&y) ans+=c[x][y];
	return ans;
}
inline void update(int L,int R,int l,int r){
	if (l>r) return;
	if (L==R){
		for (rr int i=l;i<=r;++i)
		    if (q[i].rk) ans[q[i].rk]=b[L];
		return;
	}
	rr int mid=(L+R)>>1,tot1=0,tot2=0;
	for (rr int i=l;i<=r;++i)
	if (!q[i].rk){
		if (q[i].w<=b[mid]) add(q[i].x2,q[i].y2,1);
	    q[i].w>b[mid]?q2[++tot2]=q[i]:q1[++tot1]=q[i];
	}else{
		rr int sum=query(q[i].x2,q[i].y2)-query(q[i].x1-1,q[i].y2)-query(q[i].x2,q[i].y1-1)+query(q[i].x1-1,q[i].y1-1);
	    sum<q[i].w?(q[i].w-=sum,q2[++tot2]=q[i]):q1[++tot1]=q[i]; 
	}
	for (rr int i=1;i<=tot1;++i)
	    if (!q1[i].rk) add(q1[i].x2,q1[i].y2,-1);
	for (rr int i=l;i<l+tot1;++i) q[i]=q1[i-l+1];
	for (rr int i=l+tot1;i<=r;++i) q[i]=q2[i-l-tot1+1];
	update(L,mid,l,l+tot1-1);
	update(mid+1,R,l+tot1,r); 
}
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=n;++j)
	    q[++tot]=(rec){0,0,i,j,b[++cnt]=iut(),0};
	sort(b+1,b+1+cnt),cnt=unique(b+1,b+1+cnt)-b-1;
	for (rr int i=1;i<=m;++i){
		rr int x1=iut(),y1=iut(),x2=iut(),y2=iut(),k=iut();
		q[++tot]=(rec){x1,y1,x2,y2,k,i};
	}
	update(1,cnt,1,tot);
	for (rr int i=1;i<=m;++i)
	    print(ans[i]),putchar(10);
	return 0;
}

JZOJ 3410 Tree

题目

给出一张无向图,问构造一棵生成树,如何使标准差最小


分析

要不是我比赛写错了一点点,我就90了
那么我们得让选择的边尽量接近于平均数,考虑枚举边权,按照绝对值排序,跑一次Kruskal
时间复杂度 O ( m 2 l o g 2 m ) O(m^2log_2 m) O(m2log2m),然而非正解,因为这样肯定会有偏差,
所以得枚举基准值,时间复杂度 O ( 4000 m l o g 2 m ) O(4000mlog_2m) O(4000mlog2m)


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
#define rr register
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
struct node{int x,y,w;}e[2011]; double stac[101];
int n,m,now,f[101]; double ans=1e18,p,now1;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline double sqr(double x){return x*x;}
bool cmp(node x,node y){return sqr(x.w-p)<sqr(y.w-p);}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
signed main(){
	n=iut(); m=iut(); rr int l,r;
	for (rr int i=1;i<=m;++i) e[i]=(node){iut(),iut(),iut()};
	sort(e+1,e+1+m,cmp),l=e[1].w,r=e[m].w;
	for (p=l;p<=r;p+=0.25){
		sort(e+1,e+1+m,cmp),now=0; rr double ave=0;
		for (rr int i=1;i<=n;++i) f[i]=i;
		for (rr int i=1;i<=m;++i){
			rr int fa=getf(e[i].x),fb=getf(e[i].y);
			if (fa==fb) continue;
			stac[++now]=e[i].w,f[fa]=fb,ave+=e[i].w;
			if (now==n-1) break;
	    }
		rr double sum=0; ave/=now;
		for (rr int i=1;i<=now;++i) sum+=sqr(stac[i]-ave);
		sum=sqrt(sum/now);
		if (ans>sum) ans=sum; 
	}
	return !printf("%.4lf",ans);
}

JZOJ 3682 CF429E Points and Segments

题目

给定 n n n条线段 [ l i , r i ] [l_i,r_i] [li,ri],然后给这些线段红蓝染色,求最后直线上任意一个点被蓝色及红色线段覆盖次数之差的绝对值不大于1


分析

假设所有节点的度数均为偶数,那么我们求这个无向图的欧拉回路。根据欧拉回路即可
求出一个可行解。
假设欧拉路径为 X i , X i + 1 … … X n {Xi,Xi+1……Xn} Xi,Xi+1Xn,对于相邻的两个点 X i , X i + 1 Xi,Xi+1 Xi,Xi+1,若 X i &gt; X i + 1 Xi&gt;Xi+1 Xi>Xi+1,那么令这条边
为红色,否则令这条边为蓝色。
这样的解显然是一组可行解,对于节点 i i i,每有一个红色区间覆盖它,为了形成欧拉回路,就必须有一个蓝色区间覆盖它。这样覆盖每个点的红色区间和蓝色区间数量相等。
然后对于存在奇点的图,显然奇点的数量一定为偶数,将所有奇点从小到大排序,设为 A 1 , A 2 , … … A n {A1,A2,……An} A1,A2,An,在 A 1 A1 A1 A 2 A2 A2, A 3 A3 A3 A 4 A4 A4,…… A n − 1 An-1 An1 A n An An之间连一条无向边,称为虚边。然后求欧拉路径即可。然后按按照之间的方法对每条边染色,接下来虚边。那么在考虑所有虚边的情况下,覆盖每个点的红色区间和蓝色区间数量相等,并且每个点最多被一个虚边覆盖。因此删除虚边的后显然也是一组可行解。


代码

#include <cstdio>
#include <cctype>
#include <algorithm> 
#define rr register
using namespace std;
const int N=200101; bool v[N<<1],col[N>>1],dfn[N];
struct node{int y,rk,next;}e[N<<1]; int n,tot,top,k=1;
int b[N],p[N>>1][2],stac[N],deg[N],ls[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void add(int x,int y,int w){
	e[++k]=(node){y,w,ls[x]},ls[x]=k;
	e[++k]=(node){x,w,ls[y]},ls[y]=k;
}
inline void dfs(int x){
	dfn[x]=1;
	for (rr int i=ls[x];i;i=e[i].next)
	if (!v[i]){
		v[i]=v[i^1]=1,col[e[i].rk]=x<e[i].y;
		dfs(e[i].y);
	} 
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i)
		b[++tot]=p[i][0]=iut(),b[++tot]=p[i][1]=iut()+1;
	sort(b+1,b+1+tot),tot=unique(b+1,b+1+tot)-b-1;
	for (rr int i=1;i<=n;++i){
		rr int x=lower_bound(b+1,b+1+tot,p[i][0])-b;
		rr int y=lower_bound(b+1,b+1+tot,p[i][1])-b;
		add(x,y,i),++deg[x],++deg[y];
	}
	for (rr int i=1,pre=0;i<=tot;++i)
	if (deg[i]&1){
	    if (pre) add(pre,i,n+1),pre=0;
		    else pre=i;
	}
	for (rr int i=1;i<=tot;++i) if (!dfn[i]) dfs(i);
	for (rr int i=1;i<=n;++i) putchar(col[i]^48),putchar(i==n?10:32);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值