noip模擬35


A. 玩游戲

考場做法用雙指針向兩側更新,當左段點左移一位時,如果右端點不滿足條件,則跳回肯定滿足的位置。復雜度玄學

題解做法是類似最長子段和,如果有一個區間和為負,則維護的指針跳過去即可


B. 排列

考慮 dp
\(f[i][j][0/1][0/1]\) 表示長度為 \(i\) 的區間合並 \(j\) 次合並完,區間左邊有沒有值,右邊有沒有值的方案數

設這個區間的最大值位置在 \(k\),那么左邊有 \(k-1\) 個值,右邊 \(i-k\) 個值,考慮左右端點和合並次數結合組合意義轉移即可

代碼實現
#include<bits/stdc++.h>
using namespace std;

const int maxn=1005;
int c[maxn][maxn];
int n,m;
long long f[maxn][maxn][2][2],mod;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
void pre(){
	c[0][0]=1;
	for(int i=1;i<=n;i++){
		c[i][0]=1;
		for(int j=1;j<=i;j++){
			c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
//			cout<<c[i][j]<<" ";
		}
	}
	return ;
}
signed main(){
	n=read();
	m=read();
	mod=read();
	pre();
//	cout<<c[5][2]<<endl;
	for(int i=0;i<=m;i++)f[0][i][0][0]=f[0][i][1][1]=f[0][i][0][1]=f[0][i][1][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=1;k<=i;k++){
				f[i][j][0][0]=(f[i][j][0][0]+f[k-1][j][0][1]*f[i-k][j][1][0]%mod*c[i-1][k-1]%mod)%mod;
				f[i][j][0][1]=(f[i][j][0][1]+f[k-1][j][0][1]*f[i-k][j-1][1][1]%mod*c[i-1][k-1]%mod)%mod;
				f[i][j][1][0]=(f[i][j][1][0]+f[k-1][j-1][1][1]*f[i-k][j][1][0]%mod*c[i-1][k-1]%mod)%mod;
				f[i][j][1][1]=(f[i][j][1][1]+(f[k-1][j][1][1]*f[i-k][j][1][1]-(f[k-1][j][1][1]-f[k-1][j-1][1][1])*(f[i-k][j][1][1]-f[i-k][j-1][1][1]))%mod*c[i-1][k-1])%mod;
				if(f[i][j][1][1]<mod)f[i][j][1][1]=f[i][j][1][1]%mod+mod;
//				cout<<f[i][j][1][1]<<endl;
			}
		}
	}
	cout<<((f[n][m][0][0]-f[n][m-1][0][0])%mod+mod)%mod;
	return 0;
}

C. 最短路

對於回去的路一定是走一段到1的路徑,再往回走一段來時的路徑
將回去的路起點和終點用 \(a\)\(b\) 表示,\(f[i][j]\) 表示起點為 \(b\),終點為 \(a\)\(g[i][j]\) 表示起點終點均為 \(a\) 點距離
轉移跑最短路實現

代碼實現
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e6+5;
const int maxm=5e7+5;
const int maxk=1005;
const int inf=0x3f3f3f3f;
int n,m,val[maxk],dis1[maxk][maxk],dis[maxn],hd[maxn],cnt,x,y;
bool vis[maxn];
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
int id(int x,int y,int z){
	return z*n*n+(x-1)*n+y;
}
struct Edge{
	int nxt,to,val;
}edge[maxm];
void add(int u,int v,int w){
//	cout<<u<<" "<<v<<" "<<w<<endl;
	edge[++cnt].nxt=hd[u];
	edge[cnt].to=v;
	edge[cnt].val=w;
	hd[u]=cnt;
	return ;
}
void spfa(){
	memset(dis,0x3f,sizeof dis);
	dis[id(n,n,0)]=0;
	queue<int>q;
	q.push(id(n,n,0));
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=hd[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(dis[v]>dis[u]+edge[i].val){
				dis[v]=dis[u]+edge[i].val;
				if(!vis[v])vis[v]=true,q.push(v);
			}
		}
	}
	return ;
}
int main(){
	n=read();
	m=read();
	for(int i=1;i<=n;i++)val[i]=read();
	memset(dis1,0x3f,sizeof dis1);
	for(int i=1;i<=m;i++){
		x=read();
		y=read();
		dis1[x][y]=val[y];
	}
	for(int i=1;i<=n;i++)dis1[i][i]=0;
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				dis1[i][j]=min(dis1[i][j],dis1[i][k]+dis1[k][j]);
//	cout<<dis1[2][4]<<endl;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			for(int k=1;k<=n;k++){
				if(dis1[j][k]!=inf&&j!=k){
					add(id(i,j,0),id(k,i,1),dis1[j][k]-val[k]);
				}
				if(dis1[i][k]!=inf&&dis1[k][j]!=inf){
					add(id(i,j,1),id(i,k,0),dis1[i][k]+dis1[k][j]);
				}
			}
		}
	}
//	cout<<"hhh"<<endl;
	spfa();
	if(dis[id(1,1,0)]==inf)puts("-1");
	else cout<<dis[id(1,1,0)]+val[1];
	return 0;
}

D. 矩形

考慮掃描線做法

當一個矩形的下邊界加入時在線段樹上區間覆蓋
上邊界去除標記

考慮如果是維護聯通性,那么當一個位置有多個矩形覆蓋,只需要和任意一個連邊即可,所以線段樹上每個點只存一種顏色,查詢時遞歸到只有一種顏色的區間然后連邊

修改時判斷將要替換的顏色和當前顏色消失的時間大小,只保留時間靠后的顏色

代碼略丑且長

代碼實現
#include<bits/stdc++.h>
using namespace std;
int read(){
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
const int maxn=2e5+5;
int n;
namespace p1{
	int fa[maxn],ans;
	struct Node{
		int x,y,xx,yy;
	}a[maxn],b,c;
	int find(int x){
		return fa[x]==x?x:fa[x]=find(fa[x]);
	}
	void merge(int x,int y){
		x=find(x);
		y=find(y);
		if(x!=y)fa[x]=y;
		return ;
	}
	void start(){
		for(int i=1;i<=n;i++){
			a[i].x=read();
			a[i].y=read();
			a[i].xx=read();
			a[i].yy=read();
		}
		for(int i=1;i<=n;i++){
			fa[i]=i;
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(i==j)continue;
				if(max(a[i].x,a[j].x)<=min(a[i].xx,a[j].xx)&&max(a[i].y,a[j].y)<=min(a[i].y,a[j].yy))merge(i,j);
				continue;
				b=a[i];
				c=a[j];
				if(b.x>c.x||b.x==c.x&&b.y>c.y)swap(b,c);
				if(c.x<=b.xx){
					if(c.y>=b.y&&c.y<=b.yy||c.yy>=b.y&&c.yy<=b.yy)merge(i,j);
				}
			}
		}
		for(int i=1;i<=n;i++){
			if(fa[i]==i)ans++;
		}
		cout<<ans;
		return ;
	}
}
namespace p2{
	int fa[maxn],x,y,xx,yy,ed[maxn],tot,ans;
	struct Node{
		int x,xx,y,op,id;
		Node(){}
		Node(int a,int b,int c,int d,int e):x(a),xx(b),y(c),op(d),id(e){}
	}a[maxn];
	
	bool cmp(Node a,Node b){
		return a.y==b.y?a.op>b.op:a.y<b.y;
	}
	int find(int x){
		return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
	}
	void merge(int x,int y){
		x=find(x);
		y=find(y);
		if(x!=y)fa[x]=y;
		return ;
	}	
	struct Seg{
		int l,r,type,num;
		bool lazy,lazy1,flag;
	}t[maxn*4];
	void build(int p,int l,int r){
		t[p].l=l;
		t[p].r=r;
		if(l==r)return ;
		int mid=l+r>>1;
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
		return ;
	}
	void update(int p){
		if(t[p<<1].num>1||t[p<<1|1].num>1)t[p].num=2;
		else if(t[p<<1].type==t[p<<1|1].type&&t[p<<1].num==1&&t[p<<1|1].num==1)t[p].num=1,t[p].type=t[p<<1].type;
		else t[p].num=t[p<<1].num+t[p<<1|1].num,t[p].type=t[p<<1].type+t[p<<1|1].type;
		if((!t[p<<1].num)||(!t[p<<1|1].num))t[p].flag=true;
		else t[p].flag=false;
		t[p].flag|=t[p<<1].flag|t[p<<1|1].flag;
		return ;
	}
	void spread(int p){
		t[p<<1].type=t[p<<1|1].type=t[p].type;
		t[p<<1].lazy1=t[p<<1|1].lazy1=0;
		t[p<<1].num=t[p<<1|1].num=t[p<<1].lazy=t[p<<1|1].lazy=1;
		t[p].lazy=0;
		return ;
	}
	void spread1(int p){
		t[p<<1].num=t[p<<1|1].num=t[p<<1].type=t[p<<1|1].type=t[p<<1].lazy=t[p<<1|1].lazy=0;
		t[p<<1].lazy1=t[p<<1|1].lazy1=1;
		t[p].lazy1=0;
		return ;
	}
	void ask(int p,int l,int r,int id){
		if(t[p].num==0)return;
		if(t[p].l>=l&&t[p].r<=r&&t[p].num==1){
//			cout<<"hhh "<<id<<" "<<t[p].type<<endl;
//			cout<<t[p].type<<endl;;
//            cout<<id<<" "<<t[p].type<<endl;
			merge(id,t[p].type);
			return ;
		}
		if(t[p].lazy1)spread1(p);
		if(t[p].lazy)spread(p);
		int mid=t[p].l+t[p].r>>1;
		if(l<=mid)ask(p<<1,l,r,id);
		if(r>mid)ask(p<<1|1,l,r,id);
		return ;
	}
	void change(int p,int l,int r,int id){
//		cout<<"hhh "<<t[p].l<<" "<<t[p].r<<" "<<t[p].num<<" "<<t[p].flag<<" "<<id<<endl;
		if(t[p].l>=l&&t[p].r<=r&&t[p].num<=1){//浼樺寲!!!
//			cout<<t[p].type<<" "<<ed[t[p].type]<<endl;
			if(ed[t[p].type]<ed[id]){
//				cout<<"ppp "<<t[p].l<<" "<<t[p].r<<" "<<id<<endl;
				t[p].type=id;
				t[p].lazy=1;
				t[p].num=1;
				t[p].lazy1=0;
				return ;
			}
			if(!t[p].flag)return ;
//			if(t[p].l==t[p].r)return ;
		}
		if(t[p].lazy1)spread1(p);
		if(t[p].lazy)spread(p);
		int mid=t[p].l+t[p].r>>1;
		if(l<=mid)change(p<<1,l,r,id);
		if(r>mid)change(p<<1|1,l,r,id);
		update(p);
		return ;
	}
	void del(int p,int l,int r,int id){
//		cout<<t[p].l<<" "<<t[p].r<<endl;
		if(t[p].l>=l&&t[p].r<=r&&t[p].num<=1){
			
			if(t[p].type==id){
				t[p].type=t[p].num=t[p].lazy=0;
				t[p].lazy1=1;
			}
			return ;
		}
		if(t[p].lazy1)spread1(p);
		if(t[p].lazy)spread(p);
		int mid=t[p].l+t[p].r>>1;
		if(l<=mid)del(p<<1,l,r,id);
		if(r>mid)del(p<<1|1,l,r,id);
		update(p);
		return ;
	}
	void start(){
		int mx=0;
		for(int i=1;i<=n;i++){
			x=read();
			y=read();
			xx=read();
			mx=max(mx,xx);
			yy=read();
			a[++tot]=Node(x,xx,y,1,i);
			a[++tot]=Node(x,xx,yy,-1,i);
			ed[i]=yy;
		}
		build(1,1,mx);
		for(int i=1;i<=n;i++)fa[i]=i;
		sort(a+1,a+tot+1,cmp);
		
//		cout<<endl;
		for(int i=1;i<=tot;i++){
//			cout<<a[i].y<<" "<<a[i].x<<" "<<a[i].xx<<" "<<a[i].id<<" "<<a[i].op<<" "<<ed[a[i].id]<<endl;
			if(a[i].op==1){
				ask(1,a[i].x,a[i].xx,a[i].id);
				change(1,a[i].x,a[i].xx,a[i].id);
			}
			else{
				del(1,a[i].x,a[i].xx,a[i].id);
			}
		}
		for(int i=1;i<=n;i++){
			if(fa[i]==i)ans++;
		}
		cout<<ans;
	}
}
int main(){
//	freopen("shuju.in","r",stdin);
//	freopen("my.out","w",stdout);
	n=read();
	p2::start();
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM