1. 程式人生 > 其它 >noip模擬40[雙指標被拋棄了....]

noip模擬40[雙指標被拋棄了....]

noip模擬40 solutions

怎麼說呢,我這兩天用單調指標用的非常的順手

第一題證都沒證就單調指標去了,導致我抱零了

所以我以後用之前一定要證一下,

關於我做題老是想不到正解這件事,我已經不糾結了,因為我完全可以亂搞出奇跡

因為第二題我亂搞+卡時,搞到了70pts

T1 送花

這個就是列舉右端點,對左區間進行更新,這個有得天獨厚的優勢

因為一旦出現重複的東西,我就直接不要這個貢獻了

線上段樹上的操作就是對上上次出現的到上次出現的區間減去貢獻

在上次出現到這次出現的區間內加上貢獻

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=1e6+5;
int n,m,c[N];
ll d[N];
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	ll now[N*4],laz[N*4];
	void pushup(int x){
		now[x]=max(now[ls],now[rs]);
		return ;
	}
	void pushdown(int x){
		//cout<<x<<endl;
		if(!laz[x])return ;
		laz[ls]+=laz[x];
		laz[rs]+=laz[x];
		now[ls]+=laz[x];
		now[rs]+=laz[x];
		laz[x]=0;
		return ;
	}
	void ins(int x,int l,int r,int ql,int qr,ll v){
		//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<endl;
		if(ql>r||qr<l||ql>qr)return ;
		if(ql<=l&&r<=qr){
			now[x]+=v;laz[x]+=v;
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid)ins(ls,l,mid,ql,qr,v);
		if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
		pushup(x);
		return ;
	}
	#undef ls
	#undef rs
}xds;
int pre[N],prx[N];
ll ans;
signed main(){
	scanf("%d%d",&n,&m);
	for(re i=1;i<=n;i++)scanf("%d",&c[i]);
	for(re i=1;i<=m;i++)scanf("%lld",&d[i]);
	for(re i=1;i<=n;i++){
		xds.ins(1,1,n,prx[c[i]]+1,pre[c[i]],-d[c[i]]);
		xds.ins(1,1,n,pre[c[i]]+1,i,d[c[i]]);
		prx[c[i]]=pre[c[i]];
		pre[c[i]]=i;
		ans=max(ans,xds.now[1]);
	}
	printf("%lld",ans);
}

T2 星空

這就是我考場出奇跡的題,直接亂搞得到70pts

具體是這樣做的,我一眼看上去,這好像是個最短路誒

最短路的話,直接dij那不就是最好的選擇嘛????

我直接把每一對點的距離放到佇列裡面,額,好像是魔改dij

然後每次提取隊頭,從這兩個端點分別向外擴充套件n個點,得到新的距離,再放到佇列中

這樣的話,保守估計,複雜度應該是\(\mathcal{O(n^3log^3n)}\)

然後我覺得這樣肯定會T ,所以就加上了一句話

int tim=clock();
if(clock()-tim>800000)break;

然後就成功的卡到了70pts,但是這個是有正確性的,如果陣列可以開出來,就能A

因為每次都是找最短的來更新

70pts
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
struct node{
	int x,y,dis;
	node(){}
	node(int a,int b,int c){
		x=a;y=b;dis=c;
	}
	bool operator < (node a)const{
		return dis>a.dis;
	}
};
priority_queue<node> q;
int n,dit[6005][6005],ans,sum;
struct pot{
	int x,y;
	pot(){}
}sca[N];
bool vis[6005][6005];
signed main(){
	//cout<<((sizeof(vis)+sizeof(dit))>>20)<<endl;
	int tim=clock();
	scanf("%d",&n);
	for(re i=1;i<=n;i++)
		scanf("%d%d",&sca[i].x,&sca[i].y);
	memset(dit,0x3f,sizeof(dit));
	for(re i=1;i<=n;i++){
		for(re j=i+1;j<=n;j++){
			dit[j][i]=dit[i][j]=abs(abs(sca[i].x-sca[j].x)-abs(sca[i].y-sca[j].y));
			q.push(node(i,j,dit[i][j]));
		}
	}
	while(!q.empty()){
		if(clock()-tim>800000)break;
		int x=q.top().x,y=q.top().y,dis=q.top().dis;q.pop();
		if(vis[x][y]||dit[x][y]!=dis)continue;
		vis[x][y]=true;
		for(re i=1;i<=n;i++){
			if(i==x||i==y)continue;
			if(vis[i][y])continue;
			int tmp=abs(abs(sca[i].x-sca[x].x)-abs(sca[i].y-sca[x].y));
			if(tmp+dis<dit[i][y]){
				dit[y][i]=dit[i][y]=tmp+dis;
				q.push(node(i,y,dit[i][y]));
			}
		}
		for(re i=1;i<=n;i++){
			if(i==x||i==y)continue;
			if(vis[x][i])continue;
			int tmp=abs(abs(sca[i].x-sca[y].x)-abs(sca[i].y-sca[y].y));
			if(tmp+dis<dit[x][i]){
				dit[x][i]=dit[i][x]=tmp+dis;
				q.push(node(i,x,dit[x][i]));
			}
		}
	}
	ans=0x3f3f3f3f;
	for(re i=1;i<=n;i++)
		for(re j=i+1;j<=n;j++)
			if(dit[i][j])ans=min(ans,dit[i][j]);
	for(re i=1;i<=n;i++)
		for(re j=i+1;j<=n;j++)
			if(dit[i][j]==ans)sum++;
	printf("%d\n%d",ans,sum);
}

其實正解是先轉換座標系,給它斜過來,然後就像題解說的做就好了,

並查集真的挺好用的,然後用vector維護距離為ans1的並查集就行了

轉化座標系是真的妙,自己手摸一下就有了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
int n;
struct node{
	int xp,yp,x,y,id;
	node(){}
}sca[N];
struct BSU{
	int fa[N],siz[N];
	BSU(){for(re i=1;i<=100000;i++)fa[i]=i,siz[i]=1;}
	int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
	void merge(int x,int y){
		if(!x||!y)return ;
		int fx=find(x),fy=find(y);
		if(fx==fy)return ;
		fa[fx]=fy;siz[fy]+=siz[fx];
	}
}bsu;
int mpx[N*4],mpy[N*4],bas=2e5+1,ans1=0x3f3f3f3f,ans2=0;
bool cmx(node a,node b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
bool cmy(node a,node b){if(a.y!=b.y)return a.y<b.y;return a.x<b.x;}
vector<pair<int,int> > vec[N*4];
signed main(){
	scanf("%d",&n);
	for(re i=1;i<=n;i++){
		scanf("%d%d",&sca[i].xp,&sca[i].yp);
		sca[i].x=sca[i].xp+sca[i].yp;
		sca[i].y=sca[i].xp-sca[i].yp;
		sca[i].id=i;
	}
	for(re i=1;i<=n;i++){
		int xx=sca[i].x+bas,yy=sca[i].y+bas;
		if(mpx[xx])bsu.merge(i,mpx[xx]);
		else mpx[xx]=i;
		if(mpy[yy])bsu.merge(i,mpy[yy]);
		else mpy[yy]=i;
	}
	sort(sca+1,sca+n+1,cmx);
	for(re i=1;i<n;i++){
		int tmp=min(abs(sca[i].x-sca[i+1].x),abs(sca[i].y-sca[i+1].y));
		int fx=bsu.find(sca[i].id),fy=bsu.find(sca[i+1].id);
		vec[tmp].push_back(make_pair(min(fx,fy),max(fx,fy)));
		if(tmp)ans1=min(ans1,tmp);
	}
	sort(sca+1,sca+n+1,cmy);
	for(re i=1;i<n;i++){
		int tmp=min(abs(sca[i].x-sca[i+1].x),abs(sca[i].y-sca[i+1].y));
		int fx=bsu.find(sca[i].id),fy=bsu.find(sca[i+1].id);
		vec[tmp].push_back(make_pair(min(fx,fy),max(fx,fy)));
		if(tmp)ans1=min(ans1,tmp);
	}
	printf("%d\n",ans1);
	sort(vec[ans1].begin(),vec[ans1].end());
	vec[ans1].erase(unique(vec[ans1].begin(),vec[ans1].end()),vec[ans1].end());
	//cout<<vec[ans1].size()<<endl;
	for(re i=0;i<vec[ans1].size();i++){
		if(vec[ans1][i].first==vec[ans1][i].second)continue;
		//cout<<vec[ans1][i].first<<" "<<vec[ans1][i].second<<endl;
		ans2+=bsu.siz[vec[ans1][i].first]*bsu.siz[vec[ans1][i].second];
	}
	printf("%d\n",ans2);
}

T3 零一串

這個我也沒有改過,因為,我懶得動了

直接把每個1的移動的序列搞出來

然後就用佇列維護就好了,維護這個序列中0的相對位置

沽~~~~