2018.10.9模拟赛

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/82989521

2018.10.9模拟赛

T1 trade

正解:贪心

据说lyd讲过但并没有印象QAQ,考场上现推浪费了不少时间

其实就开个小根堆,每次把堆顶取出来看它是不是比当前的 a [ i ] a[i] 小,如果小的话就把它替换成 a [ i ] a[i]

然后再把 a [ i ] a[i] push进去

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define maxn 100005
#define LL long long
using namespace std;
int n,a[maxn];
LL ans;
priority_queue< pair<int,int> > q;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

int main(){
	freopen("trade.in","r",stdin);
	freopen("trade.out","w",stdout);
	n=rd();
	for(int i=1;i<=n;i++) a[i]=rd();
	for(int i=1;i<=n;i++){
		if(!q.empty()){
			int x=q.top().second;
			if(a[x]<a[i]){
				q.pop(); ans+=a[i]-a[x];
				q.push(make_pair(-a[i],i));
			}
		}
		q.push(make_pair(-a[i],i));
	}
	printf("%lld\n",ans);
	return 0;
}
//5
//1 1 5 3 6

T2 sum

正解是莫队,但我不会莫队呜呜呜我果然是机房最菜的那个,然后就胡乱写了一堆暴力拿了60分

把询问离线然后分块,块外按n排序,快内按m排序

因为可以很容易地从 S i , j S_{i,j} 转移到 S i + 1 , j S_{i+1,j} 或者 S i , j + 1 S_{i,j+1} 所以只要维护两个指针转移就好了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 100005
#define LL long long
using namespace std;
int q,block;
LL fac[maxn],inv[maxn],ans[maxn];
const int mod=1e9+7,inv2=500000004;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

struct Query{
	int n,m,id,pos;
	bool operator <(const Query &x) const{
		return pos==x.pos?m<x.m:pos<x.pos;
	}
}a[maxn];

inline LL qpow(LL x,int k){
	LL ret=1;
	while(k){
		if(k&1) (ret*=x)%=mod;
		(x*=x)%=mod; k>>=1;
	} return ret;
}

inline void prework(){
	fac[0]=1; inv[1]=1;
	for(int i=1;i<=100000;i++)
		fac[i]=(fac[i-1]*i)%mod;
	inv[100000]=qpow(fac[100000],mod-2);
	for(int i=100000;i>=1;i--) inv[i-1]=(inv[i]*i)%mod;
}

inline LL C(int n,int m){
	return fac[n]*inv[m]%mod*inv[n-m]%mod; 
}

inline void solve(){
	sort(a+1,a+q+1);
	int nn=0,nm=0; LL cur=1;
	for(int i=1;i<=q;i++){
		int x=a[i].n,y=a[i].m;
		while(nn<x){
			(cur*=2)%=mod; cur=(cur-C(nn,nm)+mod)%mod; nn++;
		}
		while(nm<y){
			nm++;(cur+=C(nn,nm))%=mod;
		}
		while(nn>x){
			nn--;cur=(cur+C(nn,nm))%mod; (cur*=inv2)%=mod;
		}
		while(nm>y){
			cur=(cur-C(nn,nm)+mod)%mod; nm--;
		}
		ans[a[i].id]=cur;
	}
	for(int i=1;i<=q;i++)
		printf("%lld\n",ans[i]);
}

int main(){
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	int t=rd(); q=rd(); block=sqrt(q);
	for(int i=1;i<=q;i++){
		a[i].n=rd(),a[i].m=rd(); a[i].id=i; a[i].pos=a[i].n/block;
	}
	prework(); solve();
	return 0;
}
/*
1
5
1 1
2 1
3 2
4 3
5 5
*/

T3 building

本场最毒瘤的题了吧···不过部分分分的很清楚,打了40的暴力qwq

正解讲了两种:

第一种是xcc讲的,就是用各种 v e c t o r vector 存横块和竖块的信息,当 u = 0 u=0 的时候非常简单,只需要差分 + + 前缀和就好了

但是当 u = 1 u=1 的时候就有些麻烦了,首先可以用并查集维护连通性,顺便算出联通块个数,然后一行一行的扫

扫描二维码关注公众号,回复: 3587691 查看本文章

一边扫一边用维护,每次从上一行转移过来,这个可以用 v e c t o r vector 里面存的信息办到

但是代码非常长并且细节很多,一定要脑子清醒的时候写

第二种是某大佬讲的,就是用扫描线处理这些信息,不过好像麻烦···

于是我就写了第一种:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define int long long
#define re register
#define N 200005
using namespace std;
int n,m,k,cntq,f[N],tot,ans[N],cnt,sum[N],c[N],rt=1;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f; 
}

struct Node{
	int l,r,id;
	Node(){}
	Node(const int x,const int y,const int z){
		l=x,r=y,id=z;
	}
}tmp[N];
inline bool cmpl(const Node &a,const Node &b){return a.l<b.l;}
inline bool cmp(const Node &a,const Node &b){return a.r<b.r;}//按r排序 
vector<Node> line[N],row[N],stli[N],enli[N];
vector<int> q[2][N];

inline int find(int x){
	return x==f[x]?x:(f[x]=find(f[x]));
}

inline void add(int x,int y){
	x=find(x),y=find(y);
	if(x==y) return;
	--cnt; f[x]=y;
}

inline void solve(){
	for(re int i=1;i<=tot;i++) f[i]=i;
	for(re int i=1,t;i<=n;i++){
		cnt+=stli[i].size()+row[i].size();//从1~i行的联通块
		for(re int j=0;j<row[i].size();j++){//把上一行和它联通的都连上 
			t=lower_bound(row[i-1].begin(),row[i-1].end(),Node(0,row[i][j].l,0),cmp)-row[i-1].begin();
			for(;t<row[i-1].size()&&row[i-1][t].l<=row[i][j].r;++t)
				add(row[i][j].id,row[i-1][t].id);
			int p=row[i][j].l-1;//和左边一列联通的连上
			if(p>0){
				t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
				if(t<line[p].size()&&line[p][t].l<=i)
					add(row[i][j].id,line[p][t].id);
			}
			p=row[i][j].r+1;//右边同理
			if(p<=m){
				t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
				if(t<line[p].size()&&line[p][t].l<=i)
					add(row[i][j].id,line[p][t].id);
			}
		}//处理列 
		for(re int j=0;j<stli[i].size();j++){//上面横着的 
			t=lower_bound(row[i-1].begin(),row[i-1].end(),Node(0,stli[i][j].l,0),cmp)-row[i-1].begin();
			if(t<row[i-1].size()&&row[i-1][t].l<=stli[i][j].l&&row[i-1][t].r>=stli[i][j].l)
				add(stli[i][j].id,row[i-1][t].id);
		}
		for(re int j=0;j<enli[i].size();j++){//下面横着的 
			t=lower_bound(row[i].begin(),row[i].end(),Node(0,enli[i][j].l,0),cmp)-row[i].begin();
			if(t<row[i].size()&&row[i][t].l<=enli[i][j].l&&row[i][t].r>=enli[i][j].l)
				add(row[i][t].id,enli[i][j].id);
		}
		for(re int j=0,t;j<stli[i].size();++j){
			int p=stli[i][j].l-1;
			if(p>0){//左边竖着的 
				t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
				if(t<line[p].size()&&line[p][t].l<=i)
					add(line[p][t].id,stli[i][j].id);
			}
			p=stli[i][j].l+1;
			if(p<=m){//右边竖着的 
				t=lower_bound(line[p].begin(),line[p].end(),Node(0,i,0),cmp)-line[p].begin();
				if(t<line[p].size()&&line[p][t].l<=i)
					add(line[p][t].id,stli[i][j].id);
			}
		}
		for(re int j=0;j<q[1][i].size();j++)
			ans[q[1][i][j]]=cnt;
	}
	return; 
}

signed main(){
	freopen("building.in","r",stdin);
	freopen("building.out","w",stdout);
	int useless=rd();
	n=rd(); m=rd(); k=rd(); cntq=rd();
	for(re int i=1;i<=k;i++){
		int x1=rd(),y1=rd(),x2=rd(),y2=rd();
		if(x1==x2){
			row[x1].push_back(Node(y1,y2,0));
			sum[x1]+=y2-y1+1;
		}
		else line[y1].push_back(Node(x1,x2,0));
	}
	for(re int i=1;i<=cntq;i++){
		int a=rd(),b=rd();
		q[a][b].push_back(i);
	}
	for(re int i=1;i<=m;i++)//差分 
		for(re int j=0;j<line[i].size();j++)
			++c[line[i][j].l],--c[line[i][j].r+1];
	for(re int i=1;i<=n;i++) c[i]+=c[i-1];
	for(re int i=1;i<=n;i++)
		c[i]+=c[i-1],sum[i]+=sum[i-1];
	for(re int i=1,t;i<=n;i++){
		t=c[i]+sum[i];
		for(re int j=0;j<q[0][i].size();j++)
			ans[q[0][i][j]]=t;//求楼房个数 
	}
	if(useless>=5 && useless<=8){
		for(re int i=1;i<=cntq;i++)
			printf("%lld\n",ans[i]);
		return 0;
	} 
	for(re int i=1;i<=n;i++)
		if(row[i].size()){
			sort(row[i].begin(),row[i].end(),cmpl);
			int num=0;
			for(re int j=0;j<row[i].size();j++)//先把一行里首尾相接的连起来 
				if(num&&tmp[num].r+1==row[i][j].l) tmp[num].r=row[i][j].r;
				else tmp[++num]=row[i][j],tmp[num].id=++tot;
			row[i].clear();
			for(re int j=1;j<=num;j++) row[i].push_back(tmp[j]); 
		}
	for(re int i=1;i<=m;i++)
		if(line[i].size()){
			sort(line[i].begin(),line[i].end(),cmpl);
			int num=0;
			for(re int j=0;j<line[i].size();j++)
				if(num&&tmp[num].r+1==line[i][j].l) tmp[num].r=line[i][j].r;
				else tmp[++num]=line[i][j],tmp[num].id=++tot;
			line[i].clear();
			for(re int j=1;j<=num;j++){
				line[i].push_back(tmp[j]);//stli存的是第i行为开头的竖块信息 
				stli[tmp[j].l].push_back(Node(i,tmp[j].r,tmp[j].id));
				if(tmp[j].r+1<=n)
					enli[tmp[j].r+1].push_back(Node(i,tmp[j].l,tmp[j].id));
			}//enli存的是第i-1行为结尾的竖块信息 
		}
	solve();
	for(re int i=1;i<=cntq;i++)
		printf("%lld\n",ans[i]);
	return 0; 
}

总分 100 + 60 + 40 = 200 100+60+40=200

三校联考 r a n k 15 rank 15

本校 r a n k 2 rank 2

啊我们好菜啊

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/82989521