noip模拟37[我非常的爽]

noip模拟37 solutions

为什么爽呢??因为我这个状态极佳,但是考得不好

就是爽,没有理由的爽,因为思想淋漓尽致。每一点都考虑到了

考了4个题但是这个题也太水了吧。。。。。虽然我没有A

就是几分种就能改完的那种,有的是傻瓜题,有的是原题,后两个还是有水平。。。

我做不出来我还是要吐嘈。。。。。

T1 数列

简简单单的exgcd好吧,太强了

我只不过是考场上手动加了一个n而已,T了而已

没关系,稍微一改就过了

注意这里有一些小细节,强制所有的都是正数,强制a<b

解得的x,y的变化范围是b/gcd,a/gcd;

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e5+5;
ll n,a,b,xl[N],ys;
struct node{
	ll x,y,sum;
};
node exgcd(ll s,ll t){
	node u,v;
	if(t==0){
		v.sum=s;
		v.x=1;
		v.y=0;
		return v;
	}
	u=exgcd(t,s%t);
	v.sum=u.sum;
	v.x=u.y;
	v.y=u.x-s/t*u.y;
	return v;
}
ll out;
signed main(){
	scanf("%lld%lld%lld",&n,&a,&b);
	for(re i=1;i<=n;i++)scanf("%lld",&xl[i]),xl[i]=abs(xl[i]);
	a=abs(a);b=abs(b);
	if(a>b)swap(a,b);
	//cout<<a<<" "<<b<<endl;
	node ans=exgcd(a,b);
	a/=ans.sum;b/=ans.sum;
	bool flag=false;
	for(re i=1;i<=n;i++){
		if(xl[i]%ans.sum){
			flag=true;break;
		}
		xl[i]/=ans.sum;
		ys=xl[i]%b;
		ll x=ans.x*(ys);
		ll y=ans.y*(ys)+xl[i]/b;
		//cout<<x<<" "<<y<<endl;
		ll su=abs(x)+abs(y);
		if(x>0){
			ll s=abs(x)/b;
			x-=s*b;
			y+=s*a;
			su=min(su,abs(x)+abs(y));
			su=min(su,abs(x-b)+abs(y+a));
		}
		else if(x<0){
			ll s=abs(x)/b;
			x+=s*b;
			y-=s*a;
			su=min(su,abs(x)+abs(y));
			su=min(su,abs(x+b)+abs(y-a));
		}
		out+=su;
		//if(i==1)cout<<su<<endl;
	}
	if(flag)printf("-1");
	else printf("%lld",out);
}

T2 数对

这个题就是打乱顺序的‘队长快跑’

所以这个题只要你排好序了,这个题你就A了

考场上我觉得这个题不可做就跑路了

其实我们只需要对a+b的大小排序就好了

自己手动模拟一下就好了,一共就四种情况,有两种完全没有影响,有两种只和a+b有关

就先高潮来一个\(\mathcal{O(n^2)}\)的dp,用线段树维护就好了

60RE
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define int long long
const int N=1e5+5;
int n;
struct node{
	int a,b,w;
	bool operator < (node x)const{
		return a+b<x.a+x.b;
	}
}sca[N];
int f[3005][6005],ans;
int lsh[N],lh;
signed main(){
	scanf("%lld",&n);
	for(re i=1;i<=n;i++){
		scanf("%lld%lld%lld",&sca[i].a,&sca[i].b,&sca[i].w);
		lsh[++lh]=sca[i].a;lsh[++lh]=sca[i].b;
	}
	sort(lsh+1,lsh+lh+1);
	lh=unique(lsh+1,lsh+lh+1)-lsh-1;
	for(re i=1;i<=n;i++){
		sca[i].a=lower_bound(lsh+1,lsh+lh+1,sca[i].a)-lsh;
		sca[i].b=lower_bound(lsh+1,lsh+lh+1,sca[i].b)-lsh;
	}
	sort(sca+1,sca+n+1);
	f[0][0]=0;
	for(re i=1;i<=n;i++){
		//cout<<sca[i].a<<" "<<sca[i].b<<" "<<sca[i].w<<endl;
		for(re j=0;j<=lh;j++)f[i][j]=f[i-1][j];
		for(re j=0;j<=min(sca[i].b,sca[i].a);j++)
			f[i][sca[i].a]=max(f[i][sca[i].a],f[i-1][j]+sca[i].w);
		for(re j=sca[i].a+1;j<=sca[i].b;j++)
			f[i][j]=max(f[i][j],f[i-1][j]+sca[i].w);
	}
	for(re i=1;i<=lh;i++)ans=max(ans,f[n][i]);
	printf("%lld",ans);
}
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e5+5;
int n;
struct node{
	ll a,b,w;
	node(){}
	bool operator < (node x)const{
		return a+b<x.a+x.b;
	}
}sca[N];
ll lsh[N*2],lh;
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	ll tr[N*8],laz[N*8];
	void pushup(int x){
		tr[x]=max(tr[ls],tr[rs]);
		return ;
	}
	void pushdown(int x){
		if(!laz[x])return ;
		laz[ls]+=laz[x];
		tr[ls]+=laz[x];
		laz[rs]+=laz[x];
		tr[rs]+=laz[x];
		laz[x]=0;
		return ;
	}
	void ins_pot(int x,int l,int r,int pos,ll v){
		if(l==r){
			tr[x]=max(tr[x],v);
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(pos<=mid)ins_pot(ls,l,mid,pos,v);
		else ins_pot(rs,mid+1,r,pos,v);
		pushup(x);return ;
	}
	void ins_inr(int x,int l,int r,int ql,int qr,ll v){
		if(ql<=l&&r<=qr){
			laz[x]+=v;tr[x]+=v;
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid)ins_inr(ls,l,mid,ql,qr,v);
		if(qr>mid)ins_inr(rs,mid+1,r,ql,qr,v);
		pushup(x);return ;
	}
	ll query(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return tr[x];
		pushdown(x);
		int mid=l+r>>1;ll ret=0;
		if(ql<=mid)ret=max(ret,query(ls,l,mid,ql,qr));
		if(qr>mid)ret=max(ret,query(rs,mid+1,r,ql,qr));
		pushup(x);
		return ret;
	}
	#undef ls
	#undef rs
}xds;
ll ans;
signed main(){
	scanf("%d",&n);
	for(re i=1;i<=n;i++){
		scanf("%lld%lld%lld",&sca[i].a,&sca[i].b,&sca[i].w);
		lsh[++lh]=sca[i].a;lsh[++lh]=sca[i].b;
	}
	sort(sca+1,sca+n+1);
	sort(lsh+1,lsh+lh+1);
	lh=unique(lsh+1,lsh+lh+1)-lsh-1;
	for(re i=1;i<=n;i++){
		sca[i].a=lower_bound(lsh+1,lsh+lh+1,sca[i].a)-lsh;
		sca[i].b=lower_bound(lsh+1,lsh+lh+1,sca[i].b)-lsh;
	}
	//sort(sca+1,sca+n+1);
	for(re i=1;i<=n;i++){
		xds.ins_inr(1,1,lh,sca[i].a+1,sca[i].b,sca[i].w);
		ll tmp=xds.query(1,1,lh,1,min(sca[i].a,sca[i].b))+sca[i].w;
		xds.ins_pot(1,1,lh,sca[i].a,tmp);
		//xds.ins_inr(1,1,lh,sca[i].a+1,sca[i].b,sca[i].w);
	}
	printf("%lld",xds.tr[1]);
}

T3 最短路

就是用dij跑一个多源最短路就好了,

直接将所有的特殊点压到队列中,以这些点作为起点来跑最短路

得到的是所有非特殊点的距离最近的特殊点的距离

那么我们继续枚举每一个边,这两条边所链接的两个点如果最近的特殊点不一样就可以直接更新

这样正确性是有保证的,因为你两个特殊点要么是直接相连,要么是通过一个非特殊点相连

而当前非特殊点的最近的特殊点已经被你处理出来了,

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=2e5+5;
int n,m,p,spc[N];
struct node{
	ll dis,who;
	node(){}
	node(ll x,ll y){
		dis=x;who=y;
	}
	bool operator < (node x)const{
		return dis>x.dis;
	}
};
priority_queue<node> q;
struct edge{
	ll x,y,w;
}sca[N];
ll dit[N],whe[N],ans[N];
int to[N*2],nxt[N*2],head[N],rp;
ll val[N*2];
void add_edg(int x,int y,ll z){
	to[++rp]=y;
	val[rp]=z;
	nxt[rp]=head[x];
	head[x]=rp;
}
bool vis[N];
signed main(){
	memset(dit,0x3f,sizeof(dit));
	scanf("%d%d%d",&n,&m,&p);
	for(re i=1;i<=p;i++){
		scanf("%d",&spc[i]);
		dit[spc[i]]=0;whe[spc[i]]=spc[i];
		ans[spc[i]]=0x3f3f3f3f3f3f3f;
		q.push(node(0,spc[i]));
	}
	for(re i=1;i<=m;i++){
		scanf("%lld%lld%lld",&sca[i].x,&sca[i].y,&sca[i].w);
		add_edg(sca[i].x,sca[i].y,sca[i].w);
		add_edg(sca[i].y,sca[i].x,sca[i].w);
	}
	while(!q.empty()){
		int dis=q.top().dis,who=q.top().who;q.pop();
		if(vis[who])continue;vis[who]=true;
		for(re i=head[who];i;i=nxt[i]){
			int y=to[i];//if(vis[y])continue;
			if(dis+val[i]>dit[y])continue;
			dit[y]=dis+val[i];whe[y]=whe[who];
			q.push(node(dit[y],y));
		}
	}
	for(re i=1;i<=m;i++){
		if(whe[sca[i].x]==whe[sca[i].y])continue;
		ll tmp=dit[sca[i].x]+dit[sca[i].y]+sca[i].w;
		if(ans[whe[sca[i].x]]>tmp)ans[whe[sca[i].x]]=tmp;
		if(ans[whe[sca[i].y]]>tmp)ans[whe[sca[i].y]]=tmp;
	}
	for(re i=1;i<=p;i++)printf("%lld ",ans[spc[i]]);
}

T4 真相

这个题我考场上又想麻烦了,拿着并查集就去维护了

不如说少想了一些情况。。。

首先没有第一种的情况,直接从第一个开始走,遇到3就给当前的now^1,

这样如果到最后还是1的话,那就合法,

如果有第一种话,那么这个序列一定可以被这些人,分成许多块,

我们可以统计这些块内当说第一种话的人真的时候,说真话和假话的人的个数

就完了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e6+5;
int T,n;
struct node{
	int typ,num;
	node(){}
}sca[N*2];
int sta[N],top;
int ji[N],cnt;
int f[N][2],g[N][2],sum;
signed main(){
	scanf("%d",&T);
	while(T--){
		top=0;cnt=0;sum=0;
		//memset(g,0,sizeof(g));
		scanf("%d",&n);
		for(re i=1;i<=n;i++){
			char a[5];scanf("%s",a);
			if(a[0]=='$'){
				sca[i].typ=1;
				scanf("%d",&sca[i].num);
				sta[++top]=i;
			}
			if(a[0]=='+')sca[i].typ=2;
			if(a[0]=='-')sca[i].typ=3;
		}
		//cout<<top<<endl;
		if(!top){
			int now=1;
			for(re i=1;i<=n;i++)if(sca[i].typ==3)now^=1;
			if(now==0)printf("inconsistent\n");
			else printf("consistent\n");
		}
		else{
			for(re i=1;i<=top;i++){
				int fro=sta[i]+1,beh,tru=0,siz=1,now=1;
				if(i==top)beh=sta[1];
				else beh=sta[i+1];
				if(fro>n)fro-=n;
				for(re j=fro;j!=beh;){
					if(now)tru++;
					if(sca[j].typ==3)now^=1;
					siz++;j++;
					if(j>n)j-=n;
				}
				ji[++cnt]=sca[beh].num;
				if(now){
					tru++;
					f[cnt][1]=tru;
					f[cnt][0]=siz-tru;
				}
				else{
					f[cnt][1]=siz-tru;
					f[cnt][0]=tru;
				}
				g[ji[cnt]][1]+=f[cnt][1];
				g[ji[cnt]][0]+=f[cnt][0];
				sum+=f[cnt][0];
			}
			bool flag=false;
			for(re i=0;i<=n;i++){
				int tmp=sum-g[i][0]+g[i][1];
				if(tmp==i){flag=true;break;}
			}
			if(flag)printf("consistent\n");
			else printf("inconsistent\n");
			for(re i=1;i<=cnt;i++)g[ji[i]][0]=g[ji[i]][1]=0;
		}
	}
}
posted @ 2021-08-13 06:09  fengwu2005  阅读(47)  评论(0编辑  收藏  举报